{
 $Id$
}
{ node manager }
{*****************************************************************************
 *
 * Purpose .............: setup
 *
 *****************************************************************************
 * Copyright (C) 1991-2008
 *
 * Vincent Coen / Ron Huiskes / Others        FIDO:   2:250/1
 * Applewood
 * Epping Road
 * Roydon, Essex, CM19 5DA
 * United Kingdom
 *
 * This file is part of FileMgr.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * FileMgr is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FileMgr; see the file COPYING.  If not, write to the Free
 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *****************************************************************************}

Procedure SortNodeIndex;
Var
  I,J : Byte;

  Procedure Swp (Var X,Y : NodeIndexType);
  Var T : NodeIndexType;
  Begin
    T := X;    X := Y;    Y := T;
  End;

begin
  writeat(1,25,7,0,expand('Sorting nodes...',80));
  for I := 1 to NodeIdx do
    for J := 1 to NodeIdx do
      begin
        if nfxt^[i].address.Zone < nfxt^[J].Address.Zone
          then Swp(nfxt^[I], nfxt^[J]) else
            if nfxt^[i].address.Zone = nfxt^[J].Address.Zone
              then if nfxt^[i].address.Net < nfxt^[J].Address.Net
                then Swp(nfxt^[I], nfxt^[J]) else
                  if nfxt^[i].address.Net = nfxt^[J].Address.Net
                    then if nfxt^[i].address.Node < nfxt^[J].Address.Node
                      then Swp(nfxt^[I], nfxt^[J]) else
                        if nfxt^[i].address.Node = nfxt^[J].Address.Node
                          then if nfxt^[i].address.Point < nfxt^[J].Address.Point
                            then Swp(nfxt^[I], nfxt^[J]);
      end;
end;


Procedure costsharing(window:byte;
                      VAR billing:boolean; VAR billgroups:booleanset;
                      VAR credit:real;  VAR warnlevel:longint;
                      VAR stoplevel:longint; VAR sendbill:byte;
                      VAR sendday:byte; VAR addpercent:byte);
Var Ch  : Char;
    T   : Byte;
    Tmp : String;

  Procedure WriteCost(x:byte);
  Begin
    Writeat(22,10,7,0,' Billing active ');
    Writeat(22,12,7,0,' Credits        ');
    Writeat(22,13,7,0,' Bill groups    ');
    Writeat(22,14,7,0,' Warn level     ');
    Writeat(22,15,7,0,' Stop level     ');
    Writeat(22,16,7,0,' Send bill      ');
    Writeat(22,17,7,0,' Add percentage ');

    writeat(1,25,7,0,replicate(79,' '));
    Case x of
     1 : Writeat(1,25,7,0,'Is billing active for this node');
     2 : Writeat(1,25,7,0,'Amount of credit cents left');
     3 : Writeat(1,25,7,0,'Billing is active for these groups');
     4 : Writeat(1,25,7,0,'Warn node when credits level reaches this level');
     5 : Writeat(1,25,7,0,'Stop sending files when credits are less then this level');
     6 : Writeat(1,25,7,0,'When to send an invoice');
     7 : Writeat(1,25,7,0,'Percentage to add to every bill for this node');
    End;

    Case x of
     1 : Writeat(22,10,kl4,kl5,' Billing active ');
     2 : Writeat(22,12,kl4,kl5,' Credits        ');
     3 : Writeat(22,13,kl4,kl5,' Bill groups    ');
     4 : Writeat(22,14,kl4,kl5,' Warn level     ');
     5 : Writeat(22,15,kl4,kl5,' Stop level     ');
     6 : Writeat(22,16,kl4,kl5,' Send bill      ');
     7 : Writeat(22,17,kl4,kl5,' Add percentage ');
    End;
  End;

  Procedure WriteCostBits;
  Begin
    Writeat(39,10,foreentry,backentry,yesno(billing));
    Writeat(39,12,foreentry,backentry,expand(real_to_Str(credit,2),14));
    writeat(39,13,foreentry,backentry,Writegroups(14,billgroups));
    Writeat(39,14,foreentry,backentry,expand(int_to_str(warnlevel),14));
    Writeat(39,15,foreentry,backentry,expand(int_to_str(stoplevel),14));
    Case sendbill of
      0 : Writeat(39,16,foreentry,backentry,'Direct');
      1 : Writeat(39,16,foreentry,backentry,'Daily ');
      2 : Writeat(39,16,foreentry,backentry,'Weekly');
      3 : Writeat(39,16,foreentry,backentry,'Monthly');
    End;
    Writeat(39,17,foreentry,backentry,expand(int_to_str(addpercent),14));
  End;

Begin
  With mwin[window] do
    Begin
      x1 := 21;
      x2 := 8;
      y1 := 53;
      y2 := 19;
      st := ' Costsharing ';
    End;
  Create_window(window);

  ch := #0;
  T := 1;

  While ch <> #27 do
    Begin
      WriteCost(t);
      WriteCostBits;
      Ch := Readkey;
      Case Ch of
        #0  : Begin
                Ch := Readkey;
                Case Ch of
                 #80 : {down}     if t < 7 then inc(t) else t := 1;
                 #72 : {up}       if t > 1 then dec(t) else t := 7;
                 #81 : {pagedown} t := 7;
                 #73 : {pageup}   t := 1;
                 #71 : {home}     t := 1;
                 #79 : {end}      t := 7;
                End;
              End;
        #9  : infoscreen;
        #26 : dosshell;
        #13 : Begin
                Case t of
                  1 : billing := not billing;
                  2 : begin
                        tmp := real_to_str(credit,2);
                        read_string(39,12,14,14,tmp,c_all);
                        credit := str_to_real(tmp);
                        if credit > warnlevel then node.warnnot := false;
                      end;
                  3 : select_groups(window+1,billgroups,false);
                  4 : begin
                        tmp := int_to_str(warnlevel);
                        read_string(39,14,7,7,tmp,c_all);
                        warnlevel := str_to_long(tmp);
                      end;
                  5 : begin
                        tmp := int_to_str(stoplevel);
                        read_string(39,15,7,7,tmp,c_all);
                        stoplevel := str_to_long(tmp);
                      end;
                  6 : begin
                        inc(sendbill);
                        if sendbill = 4 then sendbill := 0;
                      end;
                  7 : begin
                        tmp := int_to_str(addpercent);
                        read_string(39,17,3,3,tmp,c_all);
                        addpercent := str_to_int(tmp);
                      end;
                End;
              End;
      End;
    End;
  Remove_window(window);
End;


procedure maxsize(window:byte; Var bundlesize,filesize : word);
Var Ch  : Char;
    T   : Byte;
    Tmp : String;

  Procedure WriteCost(x:byte);
  Begin
    Writeat(22,10,7,0,' Max bundle size ');
    Writeat(22,11,7,0,' Max file size   ');

    writeat(1,25,7,0,replicate(79,' '));
    Case x of
     1 : Writeat(1,25,7,0,'The maximum size a packed tick bundle may get before starting a new one (in Kb)');
     2 : Writeat(1,25,7,0,'The maximum size an individual file may be if it''s sent to this node (in Kb)');
    End;

    Case x of
     1 : Writeat(22,10,kl4,kl5,' Max bundle size ');
     2 : Writeat(22,11,kl4,kl5,' Max file size   ');
    End;
  End;

  Procedure WriteCostBits;
  Begin
    Writeat(40,10,foreentry,backentry,expand(int_to_str(bundlesize),10));
    Writeat(40,11,foreentry,backentry,expand(int_to_str(filesize),10));
  End;

Begin
  With mwin[window] do
    Begin
      x1 := 21;
      x2 := 8;
      y1 := 53;
      y2 := 13;
      st := ' Maximum size ';
    End;
  Create_window(window);

  ch := #0;
  T := 1;

  While ch <> #27 do
    Begin
      WriteCost(t);
      WriteCostBits;
      Ch := Readkey;
      Case Ch of
        #0  : Begin
                Ch := Readkey;
                Case Ch of
                 #80 : {down}     if t < 2 then inc(t) else t := 1;
                 #72 : {up}       if t > 1 then dec(t) else t := 2;
                 #81 : {pagedown} t := 2;
                 #73 : {pageup}   t := 1;
                 #71 : {home}     t := 1;
                 #79 : {end}      t := 2;
                End;
              End;
        #9  : infoscreen;
        #26 : dosshell;
        #13 : Begin
                Case t of
                  1 : begin
                        tmp := int_to_str(bundlesize);
                        read_string(40,10,5,5,tmp,c_all);
                        bundlesize := str_to_int(tmp);
                      end;
                  2 : begin
                        tmp := int_to_str(filesize);
                        read_string(40,11,5,5,tmp,c_all);
                        filesize := str_to_int(tmp);
                      end;
                End;
              End;
      End;
    End;

 remove_window(window)
end;


Procedure Globalnode;
Var
  ar    : array[1..12] of string[19];
  x, z,
  count : word;
  ch    : char;
  ge    : byte;
  bol   : booleanset;
  tmp   : string;
  tmp1,tmp2 : word;
  grp        : word;
  ss : archivertype;
  mal        : mailstatustype;
  Status     : SystemStatusType;
  Billing    : Boolean;
  BillGroups : BooleanSet;
  Credit     : real;
  WarnLevel  : LongInt;
  StopLevel  : LongInt;
  SendBill   : Byte;
  SendDay    : Byte;
  AddPercent : Byte;

Begin
  With Mwin[3] do
   Begin
     x1 := 27;
     x2 := 5;
     y1 := 49;
     y2 := 20;
     st := ' Global ';
   End;
  Create_Window(3);

  ar[1] := 'Available groups';
  ar[2] := 'Visible groups';
  ar[3] := 'Default new group';
  ar[4] := '.TIC file type';
  ar[5] := 'Packing method';
  ar[6] := 'Archiver';
  ar[7] := 'Maximum size';
  ar[8] := 'Default mail status';
  ar[9] := 'Manager mail status';
  ar[10]:= 'Costsharing';
  ar[11]:= 'Maximum on hold';
  ar[12]:= 'System status';

  ge := 1;
  while ge <> 0 do
    begin
      for x := 1 to 255 do bol[x] := false;
      writeat(1,25,7,0,expand('Select the option to use',79));
      choosehook := dummy;
      decwin(3);
      ge := select_window(3,12,19,@ar,ge,false);
      incwin(3);
      if ge <> 0 then
        begin
          case ge of
           1 : begin
                 writeat(1,25,7,0,expand('Activate the groups to set',79));
                 select_groups(4,bol,false);
               end;
           2 : begin
                 writeat(1,25,7,0,expand('Activate the groups to set',79));
                 select_groups(4,bol,false);
               end;
           3 : begin
                 writeat(1,25,7,0,expand('Select the group to set',79));
                 grp := Select_Group(4,1);
               end;
           4 : begin
                 grp := 0;
                 Repeat
                   case grp of
                     0 : Tmp := 'None    ';
                     1 : Tmp := 'Antique ';
                     2 : Tmp := 'Advanced';
                   end;
                   writecolor(25,7,15,0,'Tic file type: ^'+tmp);
                   ch := readkey;
                   if (ch = #13) or (ch = #32) then inc(grp);
                   if grp = 3 then grp := 0;
                 until ch = #27;
               end;
           5 : begin
                 grp := 0;
                 Repeat
                   case grp of
                     0 : Tmp := 'No packing    ';
                     1 : Tmp := 'Pack tic files';
                     2 : Tmp := 'Pack all files';
                   end;
                   writecolor(25,7,15,0,'Packing method: ^'+tmp);
                   ch := readkey;
                   if (ch = #13) or (ch = #32) then inc(grp);
                   if grp = 3 then grp := 0;
                 until ch = #27;
               end;
           6 : begin
                 ss := zip;
                 Repeat
                   writecolor(25,7,15,0,'Archiver: ^'+zipstr[ss]);
                   ch := readkey;
                   if (ch = #13) or (ch = #32) then inc(ss);
                   if ss = all then ss := zip;
                 until ch = #27;
               end;
           7 : begin
                 tmp1 := 0;
                 tmp2 := 0;
                 maxsize(4,tmp1,tmp2);
               end;
           8 : begin
                 mal := [];
                 writeat(1,25,7,0,'Select the default mail status to use');
                 Select_MailStatus(4,mal);
               end;
           9 : begin
                 mal := [];
                 writeat(1,25,7,0,'Select the default mail status to use');
                 Select_MailStatus(4,mal);
               end;
          10 : begin
                 Billing  := false;
                 fillchar(BillGroups,sizeof(billgroups),0);
                 Credit := 0;     WarnLevel := 0;
                 StopLevel := 0;  SendBill := 0;
                 SendDay := 0;    AddPercent := 0;
                 writeat(1,25,7,0,'Select the costsharing options to use');
                 costsharing(4,billing,billgroups,credit,warnlevel,stoplevel,
                   sendbill,sendday,addpercent);
               end;
          11 : begin
                 tmp := '';
                 writeat(1,25,7,0,'Maximum on hold:           ');
                 read_string(18,25,6,6,tmp,c_all);
               end;
          12 : begin
                 status := [];
                 Writeat(1,25,7,0,'Set all bits to the correct status');
                 Select_SystemStatus(4,status);
               end;
          end;

          writeat(1,25,7,0,replicate(79,' '));
          case ge of
           1,
           2 : writeat(1,25,7,0,'Update all nodes with selected groups ? (Y/N)');
           3 : writeat(1,25,7,0,'Update all nodes with default new group '+int_to_str(grp)+' ? (Y/N)');
           4 : writeat(1,25,7,0,'Update all nodes with tic type "'+strip('B',' ',tmp)+'" ? (Y/N)');
           5 : writeat(1,25,7,0,'Update all nodes with packing method "'+strip('B',' ',tmp)+'" ? (Y/N)');
           6 : writeat(1,25,7,0,'Update all nodes with archiver "'+zipstr[ss]+'" ? (Y/N)');
           7 : writeat(1,25,7,0,'Update all nodes with bundle size of '+int_to_str(tmp1)+' and filesize of '
                  +int_to_str(tmp2)+' ? (Y/N)');
           8 : writeat(1,25,7,0,'Update all nodes with selected default mail status ? (Y/N)');
           9 : writeat(1,25,7,0,'Update all nodes with selected manager mail status ? (Y/N)');
          10 : writeat(1,25,7,0,'Update all nodes with selected costsharing options ? (Y/N)');
          11 : writeat(1,25,7,0,'Update all nodes with '+tmp+' Kb maximum on hold ? (Y/N)');
          12 : writeat(1,25,7,0,'Update all nodes with selected status bits ? (Y/N)');
          end;

          ch := #0;
          while not (ch in ['y','Y','n','N',#27]) do ch := readkey;

          {selected nodes or all nodes?}

          If ch in ['y','Y'] then
            begin
              for x := 1 to nodeidx do
                begin
                  writeat(1,25,7,0,expand(node2str(nfxt^[x].address),79));
                  seek(nf,nfxt^[x].noderec);
                  blockread(nf,node,sizeof(node),count);

                  case ge of
                    1 : begin
                          for z := 1 to 255 do
                           if bol[z] then node.groups[z] := true;
                        end;
                    2 : begin
                          for z := 1 to 255 do
                            if bol[z] then node.visible[z] := true;
                        end;
                    3 : node.newgroup := grp;
                    4 : node.tictype := grp;
                    5 : begin
                          case grp of
                            0 : begin
                                  node.defstatus := node.defstatus - [packtic];
                                  node.defstatus := node.defstatus - [packfile];
                                end;
                            1 : begin
                                  node.defstatus := node.defstatus + [packtic];
                                  node.defstatus := node.defstatus - [packfile];
                                end;
                            2 : begin
                                  node.defstatus := node.defstatus - [packtic];
                                  node.defstatus := node.defstatus + [packfile];
                                end;
                          end;
                        end;
                    6 : node.archiver := ss;
                    7 : begin
                          node.maxsize := tmp1;
                          node.maxfilesize := tmp2;
                        end;
                    8 : node.defstatus := mal;
                    9 : node.mgrstatus := mal;
                   10 : begin
                          node.Billing := billing;
                          move(BillGroups,node.billgroups,sizeof(billgroups));
                          node.Credit := credit;
                          node.WarnLevel := warnlevel;
                          node.StopLevel := stoplevel;
                          node.SendBill := sendbill;
                          node.SendDay := sendday;
                          node.AddPercent := addpercent;
                        end;
                   11 : node.avaraging := str_to_int(tmp);
                   12 : begin
                          node.Status :=status;
                        end;
                  end;

                  seek(nf,nfxt^[x].noderec);
                  blockwrite(nf,node,sizeof(node),count);
                end;
            end;
        end;
    end;
  remove_window(3);
End;


Function Node_Ok (active:word): Boolean;
Var Found : Boolean;
    X     : Word;
Begin
  If node2str(node.address) = '' then
    Begin
      Node_Ok := False;
      AskWindow('You have to','enter a nodenumber','(F9 to abort)',[#13,#27,#32]);
    End Else
    Begin
      Found := False;
      X := 0;
      While (X < NodeIdx) and not found Do
        begin
          inc(x);
          If Samerec(nfxt^[x].address,node.address,sizeof(node.address)) then
            Found := true;
        end;
      If Found and (x <> active) then
        Begin
          AskWindow('Node','already exist','(F9 to abort)',[#13,#27,#32]);
          Node_Ok := False;
        End Else Node_Ok := True;
    End;
End;


Procedure NodeHelp( x : byte );
Begin
  Writeat(1,25,7,0,replicate(80,' '));
  Case X of
    1 : Writeat(1,25,7,0,'The nodenumber this node is identified with.');
    2 : Writeat(1,25,7,0,'Sent files for this node via this address.');
    3 : Writeat(1,25,7,0,'The name of the sysop for this node.');
    4 : Writeat(1,25,7,0,'The password used in tick files.');
    5 : Writeat(1,25,7,0,'The password needed for the remote areamanager.');
    6 : Writeat(1,25,7,0,'The groups this node has access to.');
    7 : Writeat(1,25,7,0,'The groups that are visible for this node.');
    8 : Writeat(1,25,7,0,'The default new group for this node.');
    9 : Writeat(1,25,7,0,'Which sort of tick files this node gets.');
    10: Writeat(1,25,7,0,'Which sort of packed files this node gets.');
    11: Writeat(1,25,7,0,'Which archiver to use for the packed files.');
    12: Writeat(1,25,7,0,'Maximum size of pcked bundle and individual files.');
    13: Writeat(1,25,7,0,'Mail status bits that are used by default.');
    14: Writeat(1,25,7,0,'Mail status bits that are used by areamanager mail.');
    15: Writeat(1,25,7,0,'If costsharing/billing is active for this node.');
    16: Writeat(1,25,7,0,'Maximum Kb a node may have totally on hold. [0-65535] (rest is set aside)');
    17: Writeat(1,25,7,0,'Set system status bits for this node.');
  End;
End;


Procedure NodeWrite(x:byte);
Begin
 Writeat(2,3 ,7,0,' System address      ');
 Writeat(2,4 ,7,0,' Via node            ');
 Writeat(2,5 ,7,0,' Operator name       ');
 Writeat(2,6 ,7,0,' .TIC file password  ');
 Writeat(2,7 ,7,0,' AreaMgr password    ');
 Writeat(2,8 ,7,0,' Available groups    ');
 Writeat(2,9 ,7,0,' Visible groups      ');
 Writeat(2,10,7,0,' Default new group   ');
 Writeat(2,11,7,0,' .TIC file type      ');
 Writeat(2,12,7,0,' Packing method      ');
 Writeat(2,13,7,0,' Archiver            ');
 Writeat(2,14,7,0,' Maximum size        ');
 Writeat(2,15,7,0,' Default mail status ');
 Writeat(2,16,7,0,' Manager mail status ');
 Writeat(2,17,7,0,' Costsharing         ');
 Writeat(2,18,7,0,' Maximum on hold     ');

 Writeat(2,20,7,0,' System status       ');

 Writeat(24,20,7,0,'Remote');
 Writeat(38,20,7,0,'%From');
 Writeat(51,20,7,0,'Notify');
 Writeat(64,20,7,0,'Pause');

 Writeat(24,21,7,0,'Magic');
 Writeat(38,21,7,0,'ForwRq');
 Writeat(51,21,7,0,'AddNew');
 Writeat(64,21,7,0,'Create');

 Writeat(24,22,7,0,'Netmail');

  case x of
   1 : Writeat(2,3 ,kl4,kl5,' System address      ');
   2 : Writeat(2,4 ,kl4,kl5,' Via node            ');
   3 : Writeat(2,5 ,kl4,kl5,' Operator name       ');
   4 : Writeat(2,6 ,kl4,kl5,' .TIC file password  ');
   5 : Writeat(2,7 ,kl4,kl5,' AreaMgr password    ');
   6 : Writeat(2,8 ,kl4,kl5,' Available groups    ');
   7 : Writeat(2,9 ,kl4,kl5,' Visible groups      ');
   8 : Writeat(2,10,kl4,kl5,' Default new group   ');
   9 : Writeat(2,11,kl4,kl5,' .TIC file type      ');
  10 : Writeat(2,12,kl4,kl5,' Packing method      ');
  11 : Writeat(2,13,kl4,kl5,' Archiver            ');
  12 : Writeat(2,14,kl4,kl5,' Maximum size        ');
  13 : Writeat(2,15,kl4,kl5,' Default mail status ');
  14 : Writeat(2,16,kl4,kl5,' Manager mail status ');
  15 : Writeat(2,17,kl4,kl5,' Costsharing         ');
  16 : Writeat(2,18,kl4,kl5,' Maximum on hold     ');
  17 : Writeat(2,20,kl4,kl5,' System status       ');
  end;
End;


Procedure DisplayNode;
Var Str : String;
Begin
  Writeat(24,3,foreentry,backentry,expand(node2str(node.address),56));
  Writeat(24,4,foreentry,backentry,expand(node2str(node.akaaddress),56));
  Writeat(24,5,foreentry,backentry,expand(node.sysopname,56));

  str := replicate(length(node.password),'þ');
  Writeat(24,6,foreentry,backentry,expand(str,56));
  str := replicate(length(node.mgrpassword),'þ');
  Writeat(24,7,foreentry,backentry,expand(str,56));

  writeat(24,8,foreentry,backentry,expand(Writegroups(56,node.groups),56));
  writeat(24,9,foreentry,backentry,expand(Writegroups(56,node.visible),56));

  If node.newgroup <> 0 then
    Writeat(24,10,foreentry,backentry,expand(int_to_str(node.newgroup)+' - '+gfx[node.newgroup].groupname,56)) else
      writeat(24,10,foreentry,backentry,expand(' ',56));

  case node.tictype of
    0 : writeat(24,11,foreentry,backentry,'No tic files');
    1 : writeat(24,11,foreentry,backentry,'Antique     ');
    2 : writeat(24,11,foreentry,backentry,'Advanced    ');
  end;
  if packtic in node.defstatus then writeat(24,12,foreentry,backentry,'Pack tic files') else
    if packfile in node.defstatus then writeat(24,12,foreentry,backentry,'Pack all files') else
      writeat(24,12,foreentry,backentry,'No packing    ');
  writeat(24,13,foreentry,backentry,zipstr[node.archiver]);

{  writeat(24,14,foreentry,backentry,expand(int_to_str(node.maxsize),56)); }

  writeat(24,14,foreentry,backentry,expand('Bundle: '+int_to_str(node.maxsize)+' Kb, File: '
     +int_to_str(node.maxfilesize)+' Kb.',50));

  str := '';
  if crash in node.defstatus then str := str + 'Crash ';
  if hold in node.defstatus then str := str + 'Hold ';
  if direct in node.defstatus then str := str + 'Direct';
  if str = '' then str := 'None';
  writeat(24,15,foreentry,backentry,expand(str,56));

  str := '';
  if crash in node.mgrstatus then str := str + 'Crash ';
  if hold in node.mgrstatus then str := str + 'Hold ';
  if direct in node.mgrstatus then str := str + 'Direct';
  if str = '' then str := 'None';
  writeat(24,16,foreentry,backentry,expand(str,56));

  if not node.billing then writeat(24,17,foreentry,backentry,expand('Disabled',56)) else
    begin
      writeat(24,17,foreentry,backentry,expand('Enabled, '
        +real_to_str(node.credit,0)+' credit cents left',56));
    end;
  writeat(24,18,foreentry,backentry,expand(int_to_str(node.avaraging),5));

  writeat(32,20,foreentry,backentry,yesno(remote in node.status));
  writeat(32,21,foreentry,backentry,yesno(upmagic in node.status));
  writeat(32,22,foreentry,backentry,yesno(netmail in node.status));

  writeat(45,20,foreentry,backentry,yesno(from in node.status));
  writeat(45,21,foreentry,backentry,yesno(forwreq in node.status));

  writeat(58,20,foreentry,backentry,yesno(donotify in node.status));
  writeat(58,21,foreentry,backentry,yesno(addnew in node.status));

  writeat(71,20,foreentry,backentry,yesno(pause in node.status));
  writeat(71,21,foreentry,backentry,yesno(cancreate in node.status));
End;




Function NodeEdit(active:word; newrecord:boolean) : boolean;
Var
  Ch  : Char;
  X   : Byte;
  Y   : Integer;
  Tmp : String;
  BA  : BooleanSet;
  tes : word;
  Bol : Boolean;
  abort : boolean;
Begin
  x := 1;
  ch := #0;
  abort := false;
  while ch <> #27 do
    begin
      nodewrite(x);
      nodehelp(x);
      ch := readkey;
      case ch of
        #0  : begin
                ch := readkey;
                case ch of
                 #67 : {f9}       begin ch := #27; abort := true; end;
                 #68 : {f10}      if node_ok(active) then ch := #27;
                 #80 : {down}     if x < 17 then inc(X) else x := 1;
                 #72 : {up}       if x > 1 then dec(X) else x := 17;
                 #81 : {pagedown} X := 17;
                 #73 : {pageup}   X := 1;
                 #71 : {home}     X := 1;
                 #79 : {end}      X := 17;
                end;
              end;
        #9  : infoscreen;
        #26 : dosshell;
        #13 : begin
                case x of
                  1 : begin
                        tmp := node2str(node.address);
                        read_string(24,3,56,23,tmp,c_all);
                        if tmp <> node2str(node.address) then
                          begin
                            str2node(tmp,node.address,setup.address[1],bol);
                            if not bol then askwindow('','You have to enter a valid nodenumber','',[#13,#27,#32]);
                            if node2str(node.akaaddress) = '' then move(node.address,node.akaaddress,sizeof(node.address));
                          end;
                      end;
                  2 : begin
                        tmp := node2str(node.akaaddress);
                        read_string(24,4,56,23,tmp,c_all);
                        if (tmp = node2str(node.akaaddress)) or (tmp = '') and not newrecord then
                          begin
                            tes := select_node(3,active);
                            tmp := node2str(nfxt^[tes].address);

                            Seek(nf,nfxt^[active].noderec); {node rec op goede gegevens terugzetten}
                            BlockRead(nf,node,sizeof(node),tes);
                            If tes <> sizeof(node) then
                              Begin
                                Askwindow('','Error reading nodefile.fm','',[#13,#32,#27]);
                                Exit;
                              End;

                          end;
                        str2node(tmp,node.akaaddress,setup.address[1],bol);
                        if not bol then askwindow('','You have to enter a valid nodenumber','',[#13,#27,#32]);
                      end;
                  3 : begin
                        tmp := node.sysopname;
                        read_string(24,5,56,50,tmp,c_all);
                        node.sysopname := tmp;
                      end;
                  4 : begin
                        tmp := node.password;
                        read_string(24,6,56,15,tmp,c_all);
                        node.password := tmp;
                      end;
                  5 : begin
                        tmp := node.mgrpassword;
                        read_String(24,7,56,15,tmp,c_all);
                        node.mgrpassword := tmp;
                      end;
                  6 : select_groups(3,node.groups,false);
                  7 : select_groups(3,node.visible,false);
                  8 : begin
                        tmp := int_to_str(node.newgroup);
                        read_string(24,10,56,3,tmp,c_all);
                        if (tmp = int_to_str(node.newgroup)) or (tmp = '') then
                          begin
                            if node.newgroup = 0 then node.newgroup := 1;
                            for y := 1 to 256 do ba[y] := false;
                            ba[node.newgroup] := true;
                            select_groups(3,ba,true);
                            node.newgroup := 0;
                            repeat
                              inc(node.newgroup);
                            until (node.newgroup > 255) or ba[node.newgroup];
                          end else node.newgroup := str_to_int(tmp);
                      end;
                  9 : begin
                        inc(node.tictype);
                        if node.tictype = 3 then node.tictype := 0;
                      end;
                 10 : begin
                        if packtic in node.defstatus then
                          begin
                            node.defstatus := node.defstatus - [packtic];
                            node.defstatus := node.defstatus + [packfile];
                          end else
                        if packfile in node.defstatus then
                          begin
                            node.defstatus := node.defstatus - [packfile];
                          end else
                          begin
                            node.defstatus := node.defstatus + [packtic];
                          end;
                      end;
                 11 : begin
                        inc(node.archiver);
                        if node.archiver = all then
                          node.archiver := zip;
                      end;
                 12 : begin
                        maxsize(3,node.maxsize,node.maxfilesize);
{                        tmp := int_to_str(node.maxsize);
                        read_string(24,14,5,5,tmp,c_all);
                        node.maxsize := str_to_int(tmp); }
                      end;
                 13 : select_mailstatus(3, node.defstatus);
                 14 : Select_MailStatus(3, node.mgrstatus);
                 15 : costsharing(3,node.billing,node.billgroups,node.credit,
                       node.warnlevel,node.stoplevel,node.sendbill,node.sendday,node.addpercent);
                 16 : begin
                        tmp := int_to_str(node.avaraging);
                        read_string(24,18,5,5,tmp,c_all);
                        node.avaraging := str_to_int(tmp);
                      end;
                 17 : Select_SystemStatus(3,node.status);
                end;
                displaynode;
              end;
        #27 : if newrecord then
                begin
                  if not node_ok(0) then ch := #0;
                end else
                begin
                  if not node_ok(active) then ch := #0;
                end;
      end;
    end;
  nodeedit := abort;
  nodewrite(0);
End;

procedure showareas;
var
  count,
  x, tel : word;
begin
  If MaxAvail < SizeOf(Sfxt^) then
    Begin
      Askwindow('','Not enough memory left','',[#13,#27,#32]);
      Exit;
    End Else New(Sfxt);

  Create_List;
  Writeat(1,25,7,0,expand('Working...',80));
  tel := 0;

  For X := 1 to AreaIdx do
    Begin
      Seek(af,afxt^[x].arearec);
      Blockread(af,area,sizeof(area),count);
      If count = sizeof(area) then
        Begin
          BlockRead(Af, Sfxt^, area.exportnr*sizeof(exporttype), count);
          If count = area.exportnr*sizeof(exporttype) then
            Begin
              If is_dup(area.exportnr,node.address) then            { if nop in sfxt^ }
                Begin
                  Add_To_List( expand(area.tag,17)+' '+area.name);
                  inc(tel);
                End;
            End Else
            Begin
              Dispose(sfxt);
              remove_list;
              Exit;
            End;
        End Else
        Begin
          Dispose(sfxt);
          remove_list;
          Exit;
        End;
    End;

  if tel = 0 then add_to_list('None...');
  Dispose(sfxt);

  with mwin[3] do
    begin
      x1 := 7;
      x2 := 3;
      y1 := 73;
      y2 := 22;
      st := ' Areas from '+node2str(node.address)+' ';
    end;
  create_window(3);
  Writeat(1,25,7,0,expand('These are the areas '+node2str(node.address)+' is connected to',80));

  Show_List (3, true, true, 1, 1);
  remove_window(3);
end;

Procedure NodeLoop;
Var
  Found     : Boolean;
  Ch        : Char;
  NodeBak   : NodeFileType;
  AreaBak   : AreaType;
  Tmp       : String;
  Count, x  : Word;
  active, y : Word;
  Tel       : Word;
Begin
  with mwin[2] do
    begin
      x1 := 1;
      x2 := 1;
      y1 := 80;
      y2 := 24;
      st := ' Node Manager ';
    end;
  Create_window(2);

  Nodewrite(0);
  SortNodeIndex;

  if nodeidx > 0 then active := 1 else active := 0;

  ch := #0;
  While ch <> #27 do
    Begin

      if nodeidx < 1 then
        begin
          writecolor(25,7,15,0,'^INS^-new ^ESC^-exit');
          writeat(2,1,11,0,replicate(14,'Í'));
        end else
        begin
          WriteColor(25,7,15,0,'^F2^-global ^F3^-copy ^F4^-search ^F5^-browse ^F6^-flow ^F7^-areas ^INS^-new ^DEL^-delete');
          writeat(2,1,11,0,'µ '+int_to_str(active)+' of '+int_to_str(nodeidx)+' ÆÍÍ');

          seek(nf,nfxt^[active].noderec);
          blockread(nf,node,sizeof(node),count);
          if count = sizeof(node) then
            displaynode else
              begin
                askwindow('','Error reading NODEFILE.FM','',[#13,#27,#32]);
                exit;
              end;
        end;

      Ch := readkey;
      Case ch of
       #0  : begin
               Ch := Readkey;
               Case Ch of
                 #60 : Begin {f2}
                         Globalnode;
                       End;
                 #62 : Begin {f4}
                         Writeat(1,25,7,0,replicate(80,' '));
                         Tmp := '';
                         Writeat(1,25,7,0,'Enter search string: ');
                         Read_String(22,25,40,40,tmp,c_all);
                         If Tmp <> '' then
                           Begin
                             tel := active;
                             active := 1;
                             found := false;
                             While (active < nodeidx) and not found do
                               Begin
                                 seek(nf,nfxt^[active].noderec);
                                 blockread(nf,node,sizeof(node),count);

                                 if (pos(upper(tmp),upper(node.sysopname)) <> 0) or
                                    (pos(upper(tmp),node2str(node.address)) <> 0) then found := true;

                                 if not found then Inc(active);
                               End;
                             If not found then
                               Begin
                                 AskWindow('',tmp+' not found!','',[#13,#27,#32]);
                                 active := tel;
                               End;
                           End;
                       End;
                 #63 : Begin {f5}
                         active := select_node(3,active);
                       end;
                 #64 : begin
                         ShowFlow(node.flow, node.lastmonth);
                         seek(nf,nfxt^[active].noderec);
                         blockwrite(nf,node,sizeof(node),count);
                       end;
                 #65 : showareas;  {f7}
                 #75 : {left} if active > 1 then dec(active) else write(#7);
                 #77 : {rght} if active < nodeidx then inc(active) else write(#7);
                 #71 : {home} if nodeidx > 0 then active := 1;
                 #79 : {end}  active := nodeidx;
                 #61 : begin {f3}
                         if nodeidx < 1024 then
                           begin
                             writeat(2,1,11,0,'µ '+int_to_str(nodeidx+1)+' of '+int_to_str(nodeidx+1)+' ÆÍÍ');
                             for count := 1 to 12 do
                               begin
                                 node.flow[count].bytes := -1;
                                 node.flow[count].files := -1;
                               end;
                             nodebak := node;
                             displaynode;
                             if not nodeedit(active, true) and not samerec(node,nodebak,sizeof(node)) then
                               begin
                                 if askwindow('','Save changes ? (Y/N)','',['y','Y','n','N'])  in ['y','Y'] then
                                   begin
                                     inc(nodeidx);
                                     nfxt^[nodeidx].noderec := filesize(nf);
                                     nfxt^[nodeidx].address := node.address;

                                     seek(nf,filesize(nf));
                                     blockwrite(nf,node,sizeof(node),count);
                                     if count <> sizeof(node) then askwindow('','Cannot add to NODEFILE.FM','',[#13,#27,#32]);

                                     sortnodeindex;
                                     active := 1;
                                     while (not samerec(nfxt^[active].address,node.address,sizeof(node.address))) and
                                       (active < nodeidx) do inc(active);

                                   end else node := nodebak;
                               end;
                           end;
                       end;
                 #82 : begin {ins}
                         if nodeidx < 1000 then
                           begin
                             writeat(2,1,11,0,'µ '+int_to_str(nodeidx+1)+' of '+int_to_str(nodeidx+1)+' ÆÍÍ');
                             fillchar(node,sizeof(node),#0);
                             for count := 1 to 12 do
                               begin
                                 node.flow[count].bytes := -1;
                                 node.flow[count].files := -1;
                               end;
                             node.Status    := [Remote, DoNotify, Netmail];
                             node.DefStatus := [Hold, Direct];
                             node.Archiver  := ZIP;
                             for count := 1 to 256 do node.Billgroups[count] := true;
                             node.Tictype := 1;

                             nodebak := node;
                             displaynode;
                             if not nodeedit(active,true) and not samerec(node,nodebak,sizeof(node)) then
                               begin
                                 if askwindow('','Save changes ? (Y/N)','',['y','Y','n','N'])  in ['y','Y'] then
                                   begin
                                     inc(nodeidx);
                                     nfxt^[nodeidx].noderec := filesize(nf);
                                     nfxt^[nodeidx].address := node.address;

                                     seek(nf,filesize(nf));
                                     blockwrite(nf,node,sizeof(node),count);
                                     if count <> sizeof(node) then askwindow('','Cannot add to NODEFILE.FM','',[#13,#27,#32]);

                                     sortnodeindex;
                                     active := 1;
                                     while (not samerec(nfxt^[active].address,node.address,sizeof(node.address))) and
                                       (active < nodeidx) do inc(active);

                                   end else
                                   begin
                                     node := nodebak;
                                     displaynode;
                                   end;
                               end;
                           end else askwindow('','Maximum of 1000 nodes reached','',[#13,#27,#32]);
                       end;
                 #83 : begin {del}
                         nodebak := node;
                         if askwindow('Remove node '+node2str(nodebak.address),'Are you sure?','(Y/N)',
                         ['y','n','Y','N',#27,#13]) in ['y','Y'] then
                           begin
                             seek(nf,nfxt^[active].noderec);
                             blockread(nf,node,sizeof(node),count);
                             fillchar(node.address,sizeof(node.address),0);
                             seek(nf,nfxt^[active].noderec);
                             blockwrite(nf,node,sizeof(node),count);

                             for count := active to nodeidx-1 do
                               nfxt^[count] := nfxt^[count+1];
                             dec(nodeidx);
                             if active > nodeidx then active := nodeidx;

                             fillchar(node,sizeof(node),#0);
                             displaynode;
                             if askwindow('Remove node '+node2str(nodebak.address),'from all areas also?',
                             '(Y/N)',['y','Y','N','n',#27,#13]) in ['y','Y'] then
                               Begin

                                 If MaxAvail < SizeOf(Sfxt^) then
                                   Begin
                                     Askwindow('','Not enough memory left','',[#13,#27,#32]);
                                   End Else
                                   Begin
                                     Tel := 0;
                                     New(Sfxt);
                                     For X := 1 to AreaIdx do
                                       Begin
                                         Writeat(1,25,7,0,expand(area.tag,80));
                                         Seek(af,afxt^[x].arearec);
                                         Blockread(af,area,sizeof(area),count);
                                         If count = sizeof(area) then
                                           Begin
                                             BlockRead(Af, Sfxt^, area.exportnr*sizeof(exporttype), count);
                                             If count = area.exportnr*sizeof(exporttype) then
                                               Begin
                                                 areabak := area;
                                                 count := 1;
                                                 while (count < area.exportnr) and not samerec(sfxt^[count].a,nodebak.address,
                                                   sizeof(nodebak.address)) do inc(count);
                                                 if samerec(sfxt^[count].a,nodebak.address,sizeof(nodebak.address)) then
                                                   Begin
                                                     {verander}
                                                     for y := count to area.exportnr-1 do
                                                       sfxt^[y] := sfxt^[y+1];
                                                     dec(area.exportnr);
                                                     inc(tel);
                                                     afxt^[x].arearec := filesize(af);
                                                     seek(af,filesize(af));
                                                     blockwrite(af,area,sizeof(area),count);
                                                     if count <> sizeof(area) then askwindow('','Cannot add to AREAFILE.FM',
                                                       '',[#13,#27,#32]);
                                                     blockwrite(af,sfxt^,area.exportnr*sizeof(exporttype),count);
                                                     if count <> area.exportnr*sizeof(exporttype)
                                                       then askwindow('','Cannot add to AREAFILE.FM','',[#13,#27,#32]);
                                                   End;
                                               End;
                                           End;
                                       End;
                                     Dispose(Sfxt);
                                     Askwindow('Node '+node2str(nodebak.address),'removed from'
                                       ,int_to_str(tel)+' areas', [#13,#27,#32]);
                                   End;
                               End;
                           End;
                       End;
               End;
             End;
       #9  : infoscreen;
       #26 : dosshell;
       #13 : If nodeidx <> 0 then
               Begin
                 Nodebak := node;
                 if not nodeedit(active,false) and not samerec(node,nodebak,sizeof(node)) then
                   Begin
                     if askwindow('','Save changes ? (Y/N)','',['y','Y','n','N'])  in ['y','Y'] then
                       Begin
                         move(node.address,nfxt^[active].address,sizeof(node.address));
                         seek(nf,nfxt^[active].noderec);
                         blockwrite(nf,node,sizeof(node),count);
                         if count <> sizeof(node) then askwindow('','Cannot add to NODEFILE.FM','',[#13,#27,#32]);
                       End;
                   End;
               End Else Write(#7);
      End;
    End;

  Remove_window(2);
End;
