[Back to NETWORK SWAG index] [Back to Main SWAG index] [Original]

     {
     Program Name : Tentools.Pas
     Written By   : Anonymous
     E-Mail       : nothing
     Web Page     : nothing
     Program
     Compilation  : Turbo Pascal 5.0 or later

     Program Description :

     Usefulness for BBS'S and general communications.
     For a detailed description of this code source, please,
     read the file TENTOOLS.DOC. Thank you
     }

    {$F+}
    Unit TenTools;  { SEE TENTOOLS.DOC for more information !! }

    Interface

    Uses DOS,CRT;

    CONST
       TNTI : Boolean = False; {Initialized False, this Boolean tells whether the
                         the initialization procedure has been run successfully.}
       HPointer : Integer =1;
      TPointer : Integer =1;
       CPointer : Integer =1;

    { The next three parameters can be set dynamically using the
      TenConfig Function}
                                              MaxSendBufferSize : Word = 0;  {Size of largest record to TBsend}
       MaxRecBufferSize : Word = 0;  {Size of largest record to TBreceive}
       MaxReceives : Integer = 0;   {Number of TBReceives to buffer}

    {This parameter will change if TenConfig is called with new MAXRECBUFFERSIZE}

    {   MaxRecvSets = MaxRecBufferSize div 457 + 1; }

       MAXRCVWAIT : Integer = 30; {Can be changed through SetWait function}

       SCLim : Array[0..6] of Integer = (1,99,12,28,24,60,60);
       SCMon : Array[1..12] of Integer= (31,28,31,30,31,30,31,31,30,31,30,31);
       SCMin : Array[0..6] of Integer = (0,0,1,1,0,0,0);

    TYPE

       PW8 = Array[1..8] of Char;              {Used for 8 character password  }
       SID = Array[1..12] of Char;             {Used for 12 character serverID }
       S8 = String[8];
       String80 = String[80];
       S12 = String[12];
       S15 = String[15];
       TID = Real;
       TStamp = Real;
       RcvBlock = Array[1..457] of Char;
       MAXBytes = Array[1..65521] of Byte;
       ChatBytes = Array[1..100] of Byte;
       PathString = String[128];
       NotifyTypes = (Start,Reply,Completion,ExplQueue,NoFF,IDPage,QueueTop);
       NotifySet = Set of NotifyTypes;

    {The Pre-Configuration Table and the Configuration Table are the Internal
     Structures within 10Net's Data Segment. These Tables provide information
     that is necessary for some of the functions in this toolbox. They are
     already allocated by 10Net when it is loaded and add no extra memory usage
     to the toolbox. }
       PreConfigurationTable =
       Record
          {First variable located at CTAB-51 bytes or PreCTAB }
          PCT_PhyAddr : Array[1..6] of Byte;   {Physical Adapter Address       }
          PCT_NPID    : Word;               {NPID Table Address             }
          PCT_NCBFST  : Word;               {First NCB in Pool              }
          PCT_LDEVTAB : Word;               {Local Dev Table Addr(FOXCOM)   }
          PCT_EXT_MAP : Word;               {Extended Network Err Table Addr}
          PCT_SDEVTAB : Word;               {SDEV Address                   }
          PCT_RESV1   : Integer;
          PCT_RBUFCNT : Byte;                  {Receive Buffer Counter         }
          PCT_CBUF_CNT: Byte;                  {Collect Buffer Counter         }
          PCT_TUF     : Word;               {TUF Address                    }
          PCT_ENABLE  : Byte;                  {Enable Flag                    }
          PCT_KEEP    : Byte;                  {FCB Keep Flag                  }
          PCT_RESV2   : Integer;
          PCT_DS6F    : Integer;               {Dropped Send 6F Count          }
          PCT_BFRST   : Integer;               {Buffer Chain                   }
          PCT_RESV3   : Integer;
          PCT_RTY     : Integer;               {Broadcast Retry Count          }
          PCT_TOVAL   : Byte;                  {#FFFF Loops before retry       }
          PCT_UFH     : Word;               {UFH Address                    }
          PCT_NETH    : Word;               {NetH Address                   }
          PCT_LTAB    : Word;               {LTab Address                   }
          PCT_SFH     : Word;               {SFH Address                    }
          PCT_FTAB    : Word;               {FTAB Address                   }
          PCT_RLTAB   : Word;               {RLTAB Address                  }
          PCT_SMI     : Word;               {Semaphore Address              }
          PCT_NTAB    : Word;               {NTAB Address                   }
         End;

         ConfigurationTable =
          Record
          CT_REDIR    : Word;               {Redirection Table Address      }
                                               {sometimes called CT_ADDR       }
          CT_NUM      : Byte;               {RDR_TAB Entries- 5(LPT1-3 & AUX-2)}
          CT_LNAME    : PW8;                   {Login Name                     }
          CT_NID      : Array[1..15] of Char;  {Node ID                        }
          CT_UNODE    : Array[1..3] of Char;   {Unique portion of Node Address }
          CT_FLG      : Byte;                  {Flag (DPC - Bit 6)             }
          CT_CFLG     : Byte;                  {Chat permit flag               }
          CT_PSFLG    : Byte;                  {Print and Submit Flag          }
          CT_NETFLGS  : Array[1..2] of Byte;   {10Net System Status Flag       }
          CT_L_INT    : Byte;                  {Last Interrupt                 }
          CT_L21      : Byte;                  {Last Interrupt 21              }
          CT_L6F      : Byte;                  {Last Interrupt 6F              }
          CT_L60      : Byte;                  {Last Interrupt 60              }
          CT_BFLG     : Byte;                  {Break Flag                     }
          CT_BTYP     : Integer;               {Break Type                     }
          CT_TALY     : Array[1..6] of Integer;{Send Tallies                   }

          CT_PENDF    : Byte;                  {DO_COND Pending COMMAND MAP    }
          CT_CERRF    : Byte;                  {Reserved                       }

          CT_RESV2    : Array[1..5] of Byte;   {Reserved                       }

          CT_CB       : Byte;                  {CB Channel                     }
          CT_CBCNT    : Byte;                  {Send6F on Que                  }
          CT_CBCHL    : Array[1..9] of Byte;   {Chnls 1-9 Activity             }
          CT_GATE     : Byte;                  {Bits: 1-RS232Gate, 2-Send6FGate}
          CT_RGATE    : Array[1..2] of Integer;{Dbl word ptr into Gate         }
          CT_SGATE    : Array[1..2] of Integer;{Dbl word ptr into 10Net Send   }
          CT_TIMR     : Integer;               {Address of Timer Blocks        }

          {Those variables below are only implemented in 10Net 4.1 and above}
          CT_CTSTO    : Integer;               {Datagram send time out value   }
          CT_DGRETRY  : Byte;                  {Datagram retry count           }
          CT_NCBMSES  : Byte;                  {Max Netbios sessions           }
          CT_NCBMCOMM : Byte;                  {Max Netbios command blocks     }
          CT_BUFFNUM  : Byte;                  {Number of total buffers        }
          CT_CLCTNUM  : Byte;                  {Number of Collect buffers      }
          CT_CLCTFST  : Integer;               {Offs of 1st coll. buffer chain }
          CT_DEVMASK  : Word;                  {Shared disk drives bit mask    }
          CT_DEVPRN   : Byte;                  {Shared LPT bit mask            }
          CT_DEVCOM   : Byte;                  {Shared COM bit mask            }
          CT_RESV3    : LongInt;               {Reserved}
          CT_DOSVER   : Integer;               {Dos Version(Int21/30)          }
          CT_PHYSDRVS : Byte;                  {Number of physical drives      }
          CT_RESV4    : Array[1..13] of Byte;  {Reserved}
          CT_SRVNUM   : Byte;                  {Server NCB Name Number         }
          CT_RDRNUM   : Byte;                  {Redirector NCB Name Number     }
          CT_MSGNUM   : Byte;                  {Messenger NCB Name Number      }
          CT_RESV5    : LongInt;               {Reserved}
          CT_CHATCALL : Integer;               {Chat Call Key                  }
          CT_CHATIME  : Integer;               {Chat Time Out                  }
          CT_AUTOSP1  : Byte;                  {AutoSP Flag (0=No AutoSp)      }
          CT_AUTOSP2  : Byte;                  {TMR_TIC=CT_AutoSP1*Ct_AutoSP2  }
       End;

    { What follows are structures used in function calls}

       TenNetTableRec = Record
           Alloc : Integer;
            Free : Integer;
        Reserved : Integer;
         end;

       GetTableDataRec = Record
               NodeID : SID;
               RES1   : Byte;
           ServerFlag : Byte;                  { 0=Worker, 1=Server           }
           BufferSize : Integer;               { Size of Receive Buffers      }
          TotalMemory : Integer;               { Total RAM memory in K        }
          TenNetMemory : LongInt;               { Memory alloc. to 10Net (bytes}
          AvailMemory : LongInt;               { Available Memory in Bytes    }
          TenNetTables : Array[1..22] of
                        TenNetTableRec;
           DeviceList : Array[1..64] of Char;
           SecurityFN : Array[1..64] of Char;
              AuditFN : Array[1..64] of Char;
         PrimaryDrive : Array[1..2] of Char;
            OtherJunk : Array[1..48] of Char;
        end;

       LogRec = Record
          UserName : PW8;
          PassWord : PW8;
          NodeName : SID;
       end;

       SendFormat = Record
          RNode : SID;
          DataBytes : Integer;
       End;

       PRec = Record
          TransID : TID;     {6 bytes}
           Packet : Byte;    {1}
         TPackets : Byte;    {1}
            TType : Integer; {2}
          TLength : Integer; {2}
         RespType : Byte;    {1}
       end;

       RecSet = set of 1..144;

       DateTimeRec = Record
               Year,Month,Day,Hour,Minute,Second : Integer;
        End;

       RecvRec = Record
           Sender : S12;
          TransID : TID;
        TrackRecv : RecSet;
            TType : Integer;
          TLength : Integer;
         RespType : Byte;
            RTime : Real;
               CB : Boolean;
       end;

       RecvData = Array[1..143] of RcvBlock;

       HeapRecBlock = Array[1..1310] of RecvRec;
       HeapDataBlock = Array[1..2040] of ^RecvData;

       ChRec = Record
            MsgLength : Integer;
            ChatText : Array[1..101] of Char;
       end;

       NodeRec = Record
            NID : SID;
            NT : Byte;
            UID : Array[1..8] of Char;
            Ver : Array[1..3] of Char;
       end;
       NARec = S12;
       NWRec = Record
            NID : SID;
            Ver : Array[1..4] of Byte;
       end;
       NBuffer = Array[1..140] of NodeRec;
       NABuffer = Array[1..140] of NARec;
       NWBuffer = Array[1..140] of NWRec;

       SDRec = Record             {MountList/NetUse List Record Structure}
             ServerID : S12;
              RPath : PathString;
         end;

       DriveArray = Array['A'..'Z'] of SDRec;

       PrintArray = Array['1'..'3'] of SDRec;

       LogArray = Array[0..19] of S12;
       DeviceArray = Array[0..24] of S8;
       SDev = Record         {used in Get/Set/Delete/Get User Shared Device}
            Alias : PW8;
            Path : Array[1..64] of Char;
            PassWord : PW8;
            Access : Byte;
            Mask : Array[1..4] of Char;
         end;

      StatusBlock = Record
          S_Name : Array[1..8] of Char;  {User Name}
          S_Flag : Byte;                 {0-user node,1-superstation,2-gate,
                                          3-gateactive,4-on more than 2 superstns,
                                          5-Reserved}
          S_Srvr : Array[1..24] of Byte; {Superstation Nodes logged into (reserved)}
          S_NID : SID;                   {NodeID}
          Reserved0 : Array[1..2] of Byte;

          {From Superstations:}

          S_SDRV : Array[1..2] of Byte;  {Drives avail: Bits 0-15/A-P}
          S_UFlag : Byte;                {User Service Flag:
                                          0-Mail for you     1-News for you
                                          2-Calendar for you 3-Mail for Node
                                          4-Submit ON        6-Print Permit ON
                                          6-Gate                               }
          S_SPRTRT : Byte;               {Bit 0-7 set for Printers 1-3    }
          Reserved1 : Array[1..3] of Byte;
          S_PRIU   : Byte;               {Primary Unit (0=A,1=B,etc) }
          Reserved2 : Byte;
          LoggedNodes : Array[1..444] of Char; {Logged on NodeIDS}
          S_Time : Array[1..3] of Byte;  {Time: SEC/MIN/HR}
          S_Date : Array[1..3] of Byte;  {Date: DAY/MON/YR-1980}
          Reserved3 : Array[1..6] of Byte;
      end;

       SpoolBlock = Record
        UCode : Integer;
        UFile : Array[1..11] of Char;
        UNote : Byte;
        UDays : Byte;
        UDVC : Byte;
        ULen : Integer;
        UArea : Byte;
       end;

    {These variable declarations allocate approximately 1660 bytes of memory
     to the Tentools Unit}

    VAR
       I10 : Integer;
       TenTest : Word;
       TenRegs : Registers;
       SendSet : SendFormat;
       SendBuffer : Array[1..470] of Char;
       ReceiveBuffer : Array[1..484] of Byte;
       LogData : LogRec;
       PreConfig : ^PreConfigurationTable;
       ConfigTable : ^ConfigurationTable;
       UserName : String[8];
       DataBuffer : Array[1..470] of Byte;
       PacketRec : PRec;
       ChatRec : ChRec;
       TBR : ^HeapRecBlock;
       TBD : ^HeapDataBlock;
       MaxRecvSets : Integer;
       NodeArray : ^NBuffer;
       NAArray : ^NABuffer;
       NWArray : ^NWBuffer;
       SpoolSettings : SpoolBlock;
       Spooling : Boolean;

    { The Procedures/Functions }

    Function TimeStamp : Real;

    Function StampAge(StartTime : Real): LongInt;

    Function Loaded : Boolean;

    Function Chat(NodeID : S12; VAR DBuffer {:String[n]} ) : Word;

    Function Status(NodeName : S15; VAR SBlock : StatusBlock): Word;

    Function NODEName : S12;

    Function Login(ServerID : S12;PW10Net : S8): Word;

    Function Logoff(ServerID : S12): Word;

    Function Mount(ServerID : S12; LocalDevice,RemoteDevice : Char) : Word;

    Function UnMount(LocalDrive : Char) : Word;

    Function Send(NodeID : S12; VAR DBuffer; DLength :Integer): Word;

    Function Receive(VAR DBuffer; Secs : Word; VAR Available : Integer; VAR CBMessage : Boolean): Word;

    Function GetRemoteMemory(NodeID : S12; VAR DBuffer; VAR DLength : Integer;
                             RemSeg,RemOfs : Word) : Word;

    Procedure SetCBChannel(CBChannel : Byte);

    Function TBSend(NodeID : S12;VAR DBuffer;DLength : Integer;TransactionID : TID;
                    TransType : Integer;ResponseType : Byte) : Word;

    Function TBReceive(VAR SenderID: S12;VAR DBuffer;VAR DLength : Integer;
                       VAR TransactionID : TID;VAR TransType : Integer;
                       VAR Available : Integer;VAR CB : Boolean): Word;

    Function Nodes(VAR NodeBuffer;VAR MaxNodes : Integer;SuperstationsOnly : Boolean) : Word;

    Function MountList(VAR MountTable : DriveArray;VAR PrintTable : PrintArray;VAR TableEntries : Integer): Word;

    Function LogList(VAR Logins : LogArray;VAR TableEntries : Integer): Word;

    Function GetTableData(VAR TableBuffer : GetTableDataRec): Word;

    Function MountsAvail : Integer;

    Function TenConfig(MaxSendRec,MaxRecvRec : Integer;MaxRecs : Integer) : Word;

    Function SetWait(WaitLimit : Integer): Word;

    Procedure SetUserName(UName : S8);

    Function Get10Time(NodeName : S15 ;VAR TenTime : DateTimeRec) : Word;

    Function GetDevices(ServerID : S12;VAR Device : DeviceArray;VAR DeviceCount : Integer): Word;

    Function NetUse(ServerID : S12; LocalDrive : Char; RemoteDevice : String;NetUsePassWord : S8) : Word;

    Function UnUse(LocalDrive : Char) : Word;

    Function Submit(ServerID : S12; CommandLine : String): Word;

    Function SetSpool(Printer : Byte; SpoolName : S12; Notification : NotifySet; RDays : Byte): Word;

    Function OpenSpool(NewSpoolName : S12) : Word;

    Function CloseSpool : Word;

    Function UpCase8(Str_8 : S8): S8;

    Function UpCase12(Str_12 : S12): S12;

    {******************************************************************************}

    Implementation

    Function UpCase12(Str_12 : S12): S12;
    {Expands and "Upcases" a 12 character string}
    VAR I : Integer;
    Begin
       For I:=1 to Length(Str_12) do Str_12[I]:=Upcase(Str_12[I]);
       While Length(Str_12)<12 do Str_12:=Str_12+' ';
       UpCase12:=Str_12;
    End;

    Function UpCase8(Str_8 : S8): S8;
    {Expands and "Upcases" an 8 character string}
    VAR I : Integer;
    Begin
       For I:=1 to Length(Str_8) do Str_8[I]:=Upcase(Str_8[I]);
       While Length(Str_8)<8 do Str_8:=Str_8+' ';
       UpCase8:=Str_8;
    End;

    Function TimeStamp : Real;
    {Returns a timestamp of 6 bytes ordered, Year,Month,Day,Hour(24),Minute,
     Second }
    VAR
       TS : Array[1..6] of Byte;
       TStmp : Real absolute TS;
       Year,Month,Day,DOW,Hour,Minute,Sec,Hund : Word;
    Begin
       GetTime(Hour,Minute,Sec,Hund);
       GetDate(Year,Month,Day,DOW);
       Year:=Year mod 100;
       TS[1]:=Byte(Year);
       TS[2]:=Byte(Month);
       TS[3]:=Byte(Day);
       TS[4]:=Byte(Hour);
       TS[5]:=Byte(Minute);
       TS[6]:=Byte(Sec);
       TimeStamp:=TStmp;
    End;

    Function StampAge(StartTime : Real): LongInt;
    { Returns the difference in seconds between the currenttime and the
    "Starttime" timestamp.}
    VAR
       TS1 : Array[1..6] of Byte absolute StartTime;
       TStamp2 : Real;
       TS2 : Array[1..6] of Byte absolute TStamp2;
       IArray : Array[1..6] of Integer;
       SA : Longint;
       I : Integer;
       Leaps : Integer;

     {==========}
       procedure TDec(Pos : Integer);
       begin
          if Pos>0
          then
           begin
              If (TS2[Pos]=SCMin[Pos])
              then
               begin
                  TDec(Pos-1);
                  If (Pos=3) then TS2[Pos]:=SCMon[TS2[2]]
                  else
                   begin
                      If Pos>3 then TS2[Pos]:=SCLim[Pos]-1
                      else TS2[Pos]:=SCLim[Pos];
                   end;
               end
              else
              TS2[Pos]:=TS2[Pos]-1;
           end;
       end;
     {==========}

    Begin
       FillChar(IArray,12,0);
       TStamp2:=TimeStamp;
       {Count leaps if necessary}
       Leaps:=0;
       If TS2[1]>(TS1[1]+1) then for I:=TS1[1]+1 to TS2[1]-1 do
        if (I mod 4 = 0) then Leaps:=Leaps+1;
       If TS2[1]=TS1[1]+1 then if (((TS1[1] mod 4 = 0) and (TS1[2]<=2)) or
       ((TS2[1] mod 4 =0) and (TS2[2]>2))) then Leaps:=Leaps+1;
       If (((TS1[1]=TS2[1]) and (TS1[1] mod 4 = 0)) and ((TS1[2]<=2)and (TS2[2]>2)))
        then Leaps:=Leaps+1;
       For I:=6 downto 1 do
        begin
           If (TS2[I]<TS1[I])
           then
            begin
               TS2[I]:=TS2[I]+SCLim[I];
               TDec(I-1);
            end;
           IArray[I]:=TS2[I]-TS1[I];
        end;
       IArray[3]:=IArray[3]+Leaps;
       {Using leaps now to count days}
       Leaps:=0;
       I:=TS2[2];
       While I<>TS1[2] do
        begin
           Leaps:=Leaps+SCMon[I];
           I:=I+1;
           If I>12 then I:=1;
        end;
       If IArray[1]>0 then Leaps:=Leaps+IArray[1]*365;
       Leaps:=Leaps+IArray[3];
       SA:=Leaps;
       SA:=SA*24+IArray[4];
       SA:=SA*60+IArray[5];
       StampAge:=SA*60+IArray[6];
    End;

    Function Loaded : Boolean;
    { Is 10Net Loaded? }
    TYPE
      LoadCheck = Array[1..4] of Char;
    VAR
      LPtr : ^LoadCheck;
    Begin
       With TenRegs do
        begin
           AX:=$356F;
           MSDos(TenRegs);
           LPtr:=Ptr(ES,BX-4);
           If (LPtr^[4]+Lptr^[3]+LPtr^[2]+LPtr^[1]='1XOF')
           then Loaded:=True
           else Loaded:=False;
        end;
     end;

    Function NODEName : S12;
    {Returns the current nodename }
    VAR
     I : Integer;
     NN : S12;
    Begin
       NN:='';
       If TNTI then for I:=1 to 12 do NN:=NN+ConfigTable^.CT_NID;
       NodeName:=NN;
    End;

    Function Chat(NodeID : S12; VAR DBuffer {:String[n]} ) : Word;
    { The DBuffer should be a Turbo Pascal String (length indicator in byte 0)
      The string should be no more than 100 bytes long. This function sends a
      10Net Chat message to the NodeID specified. }
    VAR
       I : Integer;
       LI : ^Byte;
       PBuffer : ^ChatBytes;
    Begin
       With TenRegs do if TNTI then
        begin
           For I:=1 to Length(NodeID) do LogData.NodeName[I]:=NodeID[I];
           If (Length(NodeID)<12) then for I:=Length(NodeID)+1 to 12 do
            LogData.NodeName[I]:=#32;
           For I:=1 to 8 do LogData.Password[I]:=#32;
           For I:=1 to 8 do LogData.UserName[I]:=ConfigTable^.CT_LName[I];
           PBuffer:=@DBuffer;
           LI:=@DBuffer;
           ChatRec.MsgLength:=Integer(LI^)+2;
           If ChatRec.MsgLength>102
           then
            begin
               ChatRec.MsgLength:=102;
               LI^:=100;
            end;
    {@#@}       Move(PBuffer^[2],ChatRec.ChatText,ChatRec.MsgLength-1);
           AX:=$0A00;
           DS:=Seg(LogData);
           BX:=Ofs(LogData);
           DX:=Ofs(ChatRec);
           Intr($6F,TenRegs);
           If Not ((Flags and $01)=0)
           then Chat:=AX
           else Chat:=0;
        end
      else
        begin
           Writeln('TENTOOLS Not Initialized');
           Halt;
        end;
    end;

    Function Status(NodeName : S15; VAR SBlock : StatusBlock): Word;
    { Returns a Block of Status information from the Nodename requested if
      that node is on the network.}
    TYPE
       A20 = Array[1..23] of Char;
    VAR
       SBP : ^A20;
       I : Integer;
    Begin
       If TNTI then with TenRegs do
        begin
           NodeName:=Upcase12(NodeName);
           FillChar(SBlock,Sizeof(StatusBlock),0);
           While Length(NodeName)<15 do NodeName:=NodeName+' ';
           Move(NodeName[1],SBlock,15);
           SBP:=@SBlock;
           Move(ConfigTable^.CT_LName,SBP^[16],8);
           AX:=$0200;
           DS:=Seg(SBlock);
           DX:=Ofs(SBlock);
           Intr($6F,TenRegs);
           If Not ((Flags and $01)=0)
           then Status:=AX
           else Status:=0;
        end
       else
        begin
           Writeln('TENTOOLS Not Initialized');
           Halt;
        end;
    end;
    Function Get10Time(NodeName : S15 ;VAR TenTime : DateTimeRec) : Word;
    {Returns the Date and Time in a DateTimeRec Record from the Node Requested.}

    VAR
       TempStatus : ^StatusBlock;
    Begin
       GetMem(TempStatus,512);
       TenTest:=Status(NodeName,TempStatus^);
       If (TenTest=0)
       then with TempStatus^ do
        begin
           with TenTime do
            begin
               Year:=S_Date[3]+1980;
               Month:=S_Date[2];
               Day:=S_Date[1];
               Hour:=S_Time[3];
               Minute:=S_Time[2];
               Second:=S_Time[1];
               Get10Time:=0;
            end;
        end
       else Get10Time:=TenTest;
       FreeMem(TempStatus,512);
    End;

    Function Login(ServerID : S12;PW10Net : S8): Word;
    { Logs into the requested server. }
    VAR
      I : Integer;
    Begin
       With TenRegs do if TNTI then
        begin
           Move(ConfigTable^.CT_LName,LogData.UserName,8);
           PW10Net:=Upcase8(PW10Net);
           For I:=1 to 8 do LogData.Password[I]:=PW10Net[I];
           ServerID:=Upcase12(ServerID);
           Move(ServerID[1],LogData.NodeName,12);
    {       Writeln(LogData.UserName,'<');
           Writeln(LogData.PassWord,'<');
           Writeln(LogData.NodeName,'<');
    }      AX:=$0000;
           DS:=Seg(LogData);
           DX:=Ofs(LogData);
           Intr($6F,TenRegs);
           If Not ((Flags and $01)=0)
           then Login:=AX
           else Login:=0;
    (*       Case AX of
                $0000 : Write('Good Login');
                $01FF : Write('No response from Superstation');
                $02FF : Write('Network Error');
                $03FF : Write('Invalid password');
                $04FF : Write('No Local Buffer available');
                $05FF : Write('Superstation device is not available');
                $06FF : Write('Node Already logged in under different name.');
                $07FF : Write('Login not valid from this node ID.');
                $09FF : Write('Node is not a superstation');
                $0AFF : Write('Node-ID already in use by another station!');
                else Write('ErrorCode ',AX);
               end; {Case}
     *)
        end
      else
       begin
          Writeln('TENTOOLS Not Initialized');
          Halt;
       end;
    end;

    Function Logoff(ServerID : S12): Word;
    { Logs off the requested server. }
    Begin
       While Length(ServerID)<12 do ServerID:=ServerID+' ';
       With TenRegs do if Loaded then
        begin
           AX:=$0100;
           DS:=Seg(ServerID);
           DX:=Ofs(ServerID)+1;
           Intr($6F,TenRegs);
           If Not ((Flags and $01)=0)
           then Logoff:=AX
           else Logoff:=0;
        end
       else Logoff:=$FFFF;
    End;

    Function Mount(ServerID : S12; LocalDevice,RemoteDevice : Char) : Word;
    { For Drive mounting, mounts drive REMOTEDRIVE at SERVERID as LOCALDRIVE
     locally; for printer mounting, use "1" for LPT1, etc. }
    VAR
     LDrive : Integer;
    Begin
       With TenRegs do if Loaded then
        begin
           If LocalDevice in ['A'..'Z'] then LDrive:=Ord(LocalDevice)-65
           else if LocalDevice in ['1'..'3'] then LDrive:=Ord(LocalDevice)-49;
           While Length(ServerID)<12 do ServerID:=ServerID+' ';
           AX:=$1700+LDrive;
           DX:=Ofs(ServerID)+1;
           DS:=Seg(ServerID);
           BL:=Ord(RemoteDevice);
           Intr($6F,TenRegs);
           If ((Flags AND 1)<>0)
           then
            begin
               Mount:=AX;
    {           TextColor(White+Blink);
               Writeln('Error: ',AX);}
            end
           else Mount:=0;
        end
       else Mount:=$FFFF;
    end;

    Function UnMount(LocalDrive : Char) : Word;
    { Unmounts previously mounted drive or printer }
    VAR
     LDrive : Integer;
     LPrint : Integer absolute LDrive;
    Begin
       If Loaded then
       With TenRegs do
        begin
           If (LocalDrive in ['A'..'Z'])
           then
            begin
               LDrive:=Ord(LocalDrive)-65;
               AX:=$1800+LDrive;
               BL:=0;
            end
           else if (LocalDrive in ['1'..'3'])
           then
            begin
               LPrint:=Ord(LocalDrive)-49;
               AX:=$1800+LPrint;
               BL:=1;
            end;
           Intr($6F,TenRegs);
           If ((Flags AND 1)<>0)
           then UnMount:=AX
           else UnMount:=0;
        end
       else UnMount:=$FFFF;
    end;

    Function NetUse(ServerID : S12; LocalDrive : Char; RemoteDevice : String;NetUsePassWord : S8) : Word;
    { Attaches to a Device at a Remote Server. The RemoteDevice can be an ALIAS }
    VAR
       I : Integer;
       DriveString : S8;
       SERVERZ : S12;
       RemoteString : String;
    Begin
       If Loaded
       then with TenRegs do
        begin
           SERVERZ:=ServerID;
           For I:=1 to Length(SERVERZ) do SERVERZ[I]:=Upcase(SERVERZ[I]);
           While ServerZ[Length(ServerZ)]=' ' do Dec(ServerZ[0]);
           For I:=1 to Length(NetUsePassword) do NetUsePassword[I]:=Upcase(NetUsePassword[I]);
           BL:=4;
           CX:=0;
           DriveString:=Upcase(LocalDrive)+':'+#0;
           DS:=Seg(DriveString);
           SI:=Ofs(DriveString)+1;
           For I:=1 to Length(RemoteDevice) do RemoteDevice[I]:=Upcase(RemoteDevice[I]);
           RemoteString:='\\'+SERVERZ+'\'+RemoteDevice+#0+NetUsePassWord;
           While RemoteString[Length(RemoteString)]=' ' do Dec(RemoteString[0]);
           RemoteString:=RemoteString+#0;
           ES:=Seg(RemoteString);
           DI:=Ofs(RemoteString)+1;
           AX:=$5F03;  {uses the Dos function call "Redirect Device"}
           MSDOS(TenRegs);
           If ((Flags AND 1)<>0)
           then
            NetUse:=AX
           else
            NetUse:=0;
        end
       else NetUse:=$FFFF;
    End;

    Function UnUse(LocalDrive : Char) : Word;
    { Detaches from a shared device at a remote server. The attachment was made
    through a Net Use (or NetUse), and the local drive letter is all that is
    needed to detach}
    VAR
       DriveString : S8;

    Begin
       If Loaded
       then with TenRegs do
        begin
           DriveString:=Upcase(LocalDrive)+':'+#0;
           DS:=Seg(DriveString);
           SI:=Ofs(DriveString)+1;
           AX:=$5F04;
           MSDos(TenRegs);
           If ((Flags AND 1)<>0)
           then
            UnUse:=AX
           else
            UnUse:=0;
        end
       else UnUse:=$FFFF;
    End;

    Function Send(NodeID : S12; VAR DBuffer; DLength :Integer): Word;
    {Send a data packet on the network to NODEID ( or on a CB Channel if
    NODEID is CB##, limited to 470 byte packets. Used within the Toolbox to
    accomplish TBSend, which allows large records to be sent.}

    VAR
     I,SR : Integer;
     CBL : String[2];
    Begin
       If DLength<=470
       then
        begin
          NodeID:=Upcase12(NodeId);
          Move(NodeID[1],SendSet.RNode,12);
          SendSet.DataBytes:=DLength;
          Move(DBuffer,SendBuffer,DLength);
          If ((NodeID[1]='C') and (NodeID[2]='B'))
          then
           begin
              CBL:=Copy(NodeID,3,2);
              If CBL[2]=' ' then CBL[0]:=#1;
              VAL(CBL,I,SR);
              If SR=0
              then
               begin
                  SendSet.RNode[2]:=#0;
                  SendSet.RNode[1]:=Char(I);
               end;
           end;
          With TenRegs do
           begin
              DS:=Seg(SendSet);
              BX:=Ofs(SendSet);
              DX:=Ofs(SendBuffer);
              AX:=$0400;
              Intr($6F,TenRegs);
              If Flags and 1 <> 0 then
              Send:=AX
              else Send:=0;
           end;
        end
       else Send:=$FFFF;
    End;

    Function Receive(VAR DBuffer; Secs : Word; VAR Available : Integer; VAR CBMessage : Boolean): Word;
    {Receive a data packet on the network in the structure below:
             data           bytes
             =====================
             SenderNodeID : 12
             Len          : 2
             Data         : (Len)
      Available is set to the number of packets available INCLUDING the
      current message. Receives data sent through the SEND function, which is
      limited to data structures of length 470 or less. TBSend and TBReceive
      (which use Send and Receive) can be used for larger structures.
    }
    VAR
     TestString : ^String80;
    Begin
       TestString:=@DBuffer;
       CBMessage:=False;
       With TenRegs do
        begin
           DX:=Ofs(DBuffer);
           DS:=Seg(DBuffer);
           CX:=Secs;
           AX:=$0500;
           Intr($6F,TenRegs);
           If (Flags and 1 <> 0) then
           Receive:=AX
           else
            begin
               Receive:=0;
               If AL=$FE then CBMessage:=True;
               Available:=ConfigTable^.CT_CBCNT+1;
            end;
        end;
    End;

    Function GetRemoteMemory(NodeID : S12; VAR DBuffer; VAR DLength : Integer; RemSeg,RemOfs : Word) : Word;
    {Copy a section of memory from a remote node to DBuffer (maximum of 470 bytes) }
    VAR
     I : Integer;

    Begin
       With TenRegs do
        begin
           AX:=$1400;
           BX:=RemSeg;
           CX:=DLength;
           SI:=RemOfs;
           DS:=Seg(DBuffer);
           DX:=Ofs(NodeID)+1;
           NodeID:=Upcase12(NodeID);
           DI:=Ofs(DBuffer);
           Intr($6F,TenRegs);
           If (Flags and 1)>0
           then GetRemoteMemory:=AX
           else
            begin
               DLength:=CX;
               GetRemoteMemory:=0;
            end;
        end;
    End;

    Procedure SetCBChannel(CBChannel : Byte);
    {      This procedure will set your "Listening" Channel to the CBCHANNEL (1
     through 40 are available) specified. TBSends to this CBChannel from other
     nodes will be available here through TBReceive. TBSends to other CBChannels
     will not be seen here. TBSends directed specifically to this node will also
     be seen here, of course.
           The advantages of CB messaging are that many nodes can be setup to
     receive messages on a particular channel, and the sender will not be held
     up waiting for a network handshake to tell him that his Send was Received.
    }
    Begin
       If TNTI
       then
        begin
           ConfigTable^.CT_CB:=CBChannel;
        end;
    End;

    Function TBSend(NodeID : S12;            {Node to send to                 }
               VAR DBuffer;                   {The data record                 }
                    DLength : Integer;        {Length (bytes) of data          }
              TransactionID : TID;            {Tag to identify record (4 bytes)}
                  TransType : Integer;        {Transaction Type - (external to
                                              this toolbox) an integer type used
                                              to maintain that one is receiving
                                              only the correct type of records.}
               ResponseType : Byte            {Not implemented}

                  ) : Word;
    { TBSend will send a large interapplication message (DBuffer) of length
    DLENGTH across the network. The TransactionID is user defineable and can be
    used to acknowledge the receipt or processing of a record to the originator.
    TransType, optional, can be used to identify the type of processing required
    of a record. The data in DBuffer can be of any structure.
         The message is effectively broken into packets, and sent with a
    "packet marker" to assist in its reconstruction when received. Unique
    Transaction IDs is essential for records larger than 457 bytes to maintain
    unique record identity. Packet Data consists of a PRec (see data Type
    definitions) and 457 bytes of the DataRec.
         The network provides handshaking with Sends and Receives if they are
    directed to a particular node. If CB# is used instead, there is no
    handshaking provided. If a node is specified, and it is not currently
    available or its 10Net SBuffers buffering is full, the sending node will
    be stuck waiting for a timeout or until the receiver or buffer space appears.
    For this reason, in some applications which can't be held up waiting, it is
    wise to use CB channel communication. (See the "SetCBChannel" function for a
    discussion of its usage.)

    }
    VAR
    RetCode : Word;
    PBuffer : ^MaxBytes;
    ILength : Integer;
    Begin
       If TNTI
       then
        begin
           If DLength<MaxSendBufferSize
           then
            begin
               NodeID:=Upcase12(NodeID);
               With PacketRec do
                begin
                   PBuffer:=@DBuffer;
                   TransID:=TransactionID;
                   TPackets:=DLength div 457;
                   If (DLength mod 457>0) then TPackets:=TPackets+1;
                   TType:=TransType;
                   TLength:=DLength;
                   RespType:=ResponseType;
                   For Packet:=1 to TPackets do
                    begin
                       If Packet=TPackets then ILength:=DLength mod 457
                       else ILength:=457;
                       Move(PacketRec,SendBuffer,13);
                       Move(PBuffer^[(Packet-1)*457+1],SendBuffer[14],ILength);
                       RetCode:=Send(NodeID,SendBuffer,ILength+13);
                       If RetCode<>0
                       then Packet:=TPackets;
                    end;
                   If RetCode<>0 then TBSend:=RetCode else TBSend:=0;
                end;
            end
           else
            begin
               Writeln('');
               Writeln('Record Size too large for TenTools Configuration.');
               Writeln('MaxSendBufferSize=',MaxSendBufferSize);
               Writeln('Record not Sent!');
               Delay(1000);
            end;
         end
        else
         begin
            Writeln('TENTOOLS Not Initialized');
            Halt;
         end;
    End;

    Function TBReceive( VAR SenderID: S12;      {Sending NodeID : String12       }
                        VAR DBuffer;           {Variable (record) to receive    }
                        VAR DLength : Integer; {Maximum length record to receive}
                  VAR TransactionID : TID;     {See description of TBSend       }
                      VAR TransType : Integer; {See description of TBSend       }
                      VAR Available : Integer; {Number of records available
                                                including the one passed back   }
                             VAR CB : Boolean) {Was this a CB transmission?     }
                             : Word;  {Return code indicates a 10Net error($XXFF)
                                       or an error in a passed parameter ($FFXX)}
    VAR
       LLRs,LLRet,I : Integer;
       SenderNode : SID absolute ReceiveBuffer;
       RLength : ^Integer;
       RPack : ^PRec;
       RcvData : ^Byte;
       CBM : Boolean;
    Begin
       If TNTI
       then
        begin
          RLength:=@ReceiveBuffer[13];
          RPack:=@ReceiveBuffer[15];
          RcvData:=@ReceiveBuffer[15+Sizeof(RPack^)];
          Repeat {process 10net receives}
             LLRet:=Receive(ReceiveBuffer,0,LLRs,CBM);
             If LLRet=0
             then
              begin
                 CPointer:=TPointer;
                 If RPack^.Packet=1
                 then CPointer:=HPointer
                 else while ((TBR^[CPointer].TransID <> RPack^.TransID)
                 and (CPointer<>HPointer)) do
                  begin
                     CPointer:=CPointer+1;
                     If CPointer>MaxReceives then CPointer:=1;
                  end;
                 If CPointer=HPointer
                 then
                  begin
                     {beginning a new record}
                     HPointer:=HPointer+1;
                     If HPointer>MaxReceives then HPointer:=1;
                     If TPointer=HPointer
                     then
                      begin
                         TPointer:=TPointer+1;
                         If TPointer>MaxReceives then TPointer:=1;
                      end;
                     TBR^[CPointer].Sender:='';
                     For I:=1 to 12 do
                     TBR^[CPointer].Sender:=TBR^[CPointer].Sender+SenderNode[I];
                     TBR^[CPointer].TransID:=RPack^.TransID;
                     TBR^[CPointer].TType:=RPack^.TType;
                     TBR^[CPointer].RTime:=TimeStamp;
                     TBR^[CPointer].TrackRecv:=[];
                     For I:=1 to RPack^.TPackets do
                     TBR^[CPointer].TrackRecv:=TBR^[CPointer].TrackRecv+[I];
                     TBR^[CPointer].Resptype:=RPack^.RespType;
                     TBR^[CPointer].TLength:=RPack^.TLength;
                     TBR^[CPointer].CB:=CBM;
                  end;
                 Move(RcvData^,TBD^[CPointer]^[RPack^.Packet],RLength^-Sizeof(RPack^));
                 TBR^[CPointer].TrackRecv:=TBR^[CPointer].TrackRecv-[RPack^.Packet];
              end;
          Until LLRet<>0;
          {Count number of records ready, keeping track of the first.}
          Available:=0;
          CPointer:=TPointer;
          While CPointer<>HPointer do
           begin
              If TBR^[CPointer].TrackRecv=[]
              then
               begin
                  Available:=Available+1;
                  If Available=1
                  then
                   begin
                      SenderID:=TBR^[CPointer].Sender;
                      DLength:=TBR^[CPointer].TLength;
                      If TBR^[CPointer].TLength>MaxRecBufferSize
                      then DLength:=MaxRecBufferSize;
                      TransactionID:=TBR^[CPointer].TransID;
                      TransType:=TBR^[CPointer].TType;
                      CB:=TBR^[CPointer].CB;
                      Move(TBD^[CPointer]^,DBuffer,DLength);
                      If CPointer<>TPointer
                      then Move(TBR^[TPointer],TBR^[CPointer],Sizeof(TBR^[1]));
                      TPointer:=TPointer+1;
                      If TPointer>MaxReceives then TPointer:=1;
                   end;
               end
              else if ((CPointer=TPointer) and (StampAge(TBR^[CPointer].RTime)>MAXRCVWAIT))
              then
               begin
                  TPointer:=TPointer+1;
                  If TPointer>MaxReceives then TPointer:=1;
               end;
              CPointer:=CPointer+1;
              If CPointer>MaxReceives then CPointer:=1;
           End;
          If Available>0 then TBReceive:=0
          else if LLRet<>$01FF then TBReceive:=LLRet
          else TBReceive:=0;
       end
      else
       begin
          Writeln('TENTOOLS Not Initialized');
          Halt;
       end;
    End;

    Function Nodes(VAR NodeBuffer;VAR MaxNodes : Integer;
                      SuperstationsOnly : Boolean) : Word;
    { A call to this function should be made with NODEBUFFER being an
     Array[1..MaxNodes] of S12. MaxNodes being the largest number of nodes you
     expect to see on the network. If the Returncode of NODES is 0, MaxNodes will
     have the actual number of nodenames returned and the array will be filled
     with their names. SuperstationsOnly is a boolean which allows nodes to be
     called to list only superstations. }

    VAR
       LIAV : LongInt;
       Av : Word;
       I,J,K,MaxRecs : Integer;
       Adjust : S12;
    Begin
       If MaxNodes>1024 then MaxNodes:=0;
       If (TNTI and (MaxNodes>0))
       then with TenRegs do
        begin
           LIAV:=MaxAvail;
           If (LIAV>=$FFFF)
           then AV:=$FFFF
           else AV:=LIAV;
           MaxRecs:=Av div 24;
           If MaxNodes<MaxRecs
           then
            begin
               MaxRecs:=MaxNodes;
               AV:=MaxRecs*24;
            end;
           GetMem(NodeArray,AV);
           AX:=$0D02;
           If SuperstationsOnly then AX:=$0D01;
           CX:=AV;
           DS:=Seg(NodeArray^);
           DX:=Ofs(NodeArray^);
           Intr($6F,TenRegs);
           NAArray:=@NodeBuffer;
           NWArray:=@NodeArray^;
           MaxNodes:=CX;
           K:=1;
           For J:=1 to MaxNodes do
            begin
               Adjust:='            ';
               for I:=1 to 12 do Case SuperStationsOnly of
               False : Adjust[I]:=NodeArray^[J].NID[I];
               True : Adjust[I]:=NWArray^[J].NID[I];
               end;
               If SuperStationsOnly
               then
                begin
                   if (NWArray^[J].Ver[1]and 1=0)
                   then
                    begin
                       NAArray^[K]:=Adjust;
                       Inc(K);
                    end
                end
               else NAArray^[J]:=Adjust;
            end;
           If (Flags and 1)>0
           then Nodes:=AX
           else Nodes:=0;
           If SuperStationsOnly then MaxNodes:=K-1;
           FreeMem(NodeArray,AV);
        end
        else if (MaxNodes<=0) then Nodes:=$FFFF;
    End;

    Function GetDevices(ServerID : S12;
                 VAR Device : DeviceArray;
                 VAR DeviceCount : Integer): Word;
    { Returns a list of devices through the Variable parameter Devices (which is
      defined as Array[1..25] of S8). Uses the Get/Set/Delete/Get User Shared
      Device (Int-$6F,Service-$15) function call.
      }
    VAR
       DCount : Integer;
       DeviceTable : SDev;
       SERVERZ : S12;
       I : Integer;
    Begin
       FillChar(Device,Sizeof(Device),0);  {initialize to all nullstrings}
       If Loaded
       then with TenRegs do
        begin
           SERVERZ:=Upcase12(ServerID);
           DCount:=0;
           Repeat
              AX:=$1501;
              BX:=DCount;
              DS:=Seg(ServerZ);
              SI:=Ofs(ServerZ)+1;
              ES:=Seg(DeviceTable);
              DI:=Ofs(DeviceTable);
              Intr($6F,TenRegs);
              If not ((Flags and 1)>0)
              then
               begin
                  Device[DCount]:=DeviceTable.Alias;
                  Inc(DCount);
               end
              else GetDevices:=AX;
           Until ((Flags and 1)>0);
           DeviceCount:=DCount;
           If DeviceCount=0 then GetDevices:=AX else GetDevices:=0;
        end
       else GetDevices:=$FFFF;
    End;

    Function GetTableData(VAR TableBuffer : GetTableDataRec): Word;
    VAR
     I : Integer;
    Begin
       If Loaded then
       With TenRegs do
        begin
           For I:=1 to 12 do TableBuffer.NodeID[I]:=ConfigTable^.CT_NID[I];
           TableBuffer.Res1:=0;
           AX:=$1D00;
           DS:=Seg(TableBuffer);
           DX:=Ofs(TableBuffer);
           Intr($6F,TenRegs);
           If not ((Flags and 1)>0)
            then GetTableData:=0
            else GetTableData:=AX;
        end
       else GetTableData:=$FFFF;
    End;

    Function MountsAvail : Integer;
     VAR
        TempTable : ^GetTableDataRec;
    Begin
       GetMem(TempTable,Sizeof(GetTableDataRec));
       If (GetTableData(TempTable^)=0) then
       MountsAvail:=TempTable^.TenNetTables[1].Free+TempTable^.TenNetTables[1].Alloc
       else MountsAvail:=0;
       FreeMem(TempTable,Sizeof(GetTableDataRec));
    End;

    Function MountList(VAR MountTable : DriveArray;VAR PrintTable : PrintArray;VAR TableEntries : Integer): Word;
    {Returns a mountlist of type DriveTable (with TableEntries as a count of
    actual table entries returned), and PrintTable of Printer reassignments.
    The caller must specify a maximum tablesize by setting table entries before
    calling. Returns with a value of 0 if it worked without any hitches, and the
    value of a 10net error if there is any problem. Will return with a value of
    $FFFF if not loaded. Will return names of Devices if any are currently
    "NetUsed".}
    VAR
      I,IB,IM : Integer;
      SA : Word;
      SR : SearchRec;
      MChar : Char;
      Highest : Integer;
      LD : ^Byte;
      HighestLocal : Integer;
      LDevBuffer : Array[1..128] of Char;
      RDevBuffer : Array[1..128] of Char;
    Begin
       If TableEntries<0 then TableEntries:=26;
       Highest:=0;
       If not Loaded
       then MountList:=$FFFF
       else with TenRegs do
        begin
           HighestLocal:=ConfigTable^.CT_PHYSDRVS;
           MountList:=0;
           Highest:=MountsAvail;
           If TableEntries>Highest then TableEntries:=Highest;
           For MChar:='A' to Char(TableEntries+64) do with MountTable[MChar] do
            begin
               If Ord(MChar)-64<=HighestLocal then ServerID:='Local       '
               else ServerID:='            ';
               RPath:=MChar;
            end;
           For MChar:='1' to '3' do with PrintTable[MChar] do
            begin
               ServerID:='            ';
               RPath:='';
            end;
           IB:=0;
           Flags:=0;
           while not ((Flags and 1)>0) do
            begin
               AX:=$1C00;
               BX:=IB;
               DS:=Seg(SendSet);
               DI:=Ofs(SendSet);
               Intr($6F,TenRegs);
               If not ((Flags and 1)>0)
               then
                begin
                   IM:=0;
                   While not ((Flags and 1)>0) do
                    begin
                       AX:=$1B00;
                       BX:=IM;
                       DS:=Seg(SendSet);
                       DX:=Ofs(SendSet);
                       Intr($6F,TenRegs);
                       If not ((Flags and 1)>0)
                       then
                        begin
                           If (AH in [65..90])
                           then
                            begin
                               MChar:=Char(AH);
                               If AH<=(TableEntries+64)
                               then
                                begin
                                   MountTable[MChar].ServerID[0]:=#12;
                                   Move(SendSet.RNode,MountTable[MChar].ServerID[1],12);
                                   MountTable[MChar].RPath:=Char(AL);
                                end;
                            end
                           else if (AH in [49..51])
                           then
                            begin
                               MChar:=Char(AH);
                               PrintTable[MChar].ServerID[0]:=#12;
                               Move(SendSet.RNode,PrintTable[MChar].ServerID[1],12);
                               PrintTable[MChar].RPath:=Char(AL);
                            end;
                        end
                       else if not (AX=$25FF)
                       then
                        begin
                           MountList:=AX;
                           TableEntries:=Highest;
                           Exit;
                        end;
                       Inc(IM);
                    end;
                  Flags:=0;
                end
               else if not (AX=$08FF) then MountList:=AX;
               Inc(IB);
            end;
           IB:=0;
            Repeat
               AX:=$5F02;
               BX:=IB;
               DS:=Seg(LDevBuffer);
               SI:=Ofs(LDevBuffer);
               ES:=Seg(RDevBuffer);
               DI:=Ofs(RDevBuffer);
               MSDOS(TenRegs);
               If not ((Flags and 1)>0)
               then with MountTable[LDevBuffer[1]] do
                begin
                   I:=3;
                   RPath:='';
                   ServerID:='';
                   While not (RDevBuffer[I]='\') do
                    begin
                       ServerID:=ServerID+RDevBuffer[I];
                       Inc(I);
                    end;
                   Inc(I);
                   While not(RDevBuffer[I]=#0) do
                    begin
                       RPath:=RPath+RDevBuffer[I];
                       Inc(I);
                    end;
                end;
               Inc(IB);
            Until ((Flags and 1)>0);
        end;
    End;

    Function LogList(VAR Logins : LogArray;VAR TableEntries : Integer): Word;
    {Returns a list of nodes that the local station is logged into. LogArray
     is a TYPE defined as Array[0..19] of String[12] and can be used in the
     calling program. }
    VAR
      IB : Integer;

    Begin
       If not Loaded
       then LogList:=$FFFF
       else with TenRegs do
        begin
           IB:=0;
           Flags:=0;
           while not ((Flags and 1)>0) do
            begin
               AX:=$1C00;
               BX:=IB;
               DS:=Seg(Sendset);
               DI:=Ofs(SendSet);
               Intr($6F,TenRegs);
               If not ((Flags and 1)>0)
               then
                begin
                   Logins[IB][0]:=#12;
                   Move(SendSet.RNode,Logins[IB][1],12);
                   Inc(IB);
                end;
               LogList:=0;
            end;
           TableEntries:=IB;
        end;
    End;

    Function Submit(ServerID : S12; CommandLine : String): Word;
    { If the local User is LOGGED INTO the node SERVERID, and the submit permit
     is ON at ServerID, and ServerID is currently at a DOS prompt, then the
     Commandline will be SUBMITTED to ServerID. If it is not currently at a DOS
     prompt, it will be SUBMITTED when it reaches a DOS prompt. }

    TYPE
       SubmitRec = Record
          Nodeid : Array[1..12] of Char;
          CLen   : Integer;
          CLine : Array[1..100] of Char;
       end;
    VAR
       ServerZ : S12;
       I : Integer;
       SRec : SubmitRec;
    Begin
       If Loaded
       then with TenRegs do
        begin
           SERVERZ:=Upcase12(ServerID);
           Move(ServerZ[1],SRec.Nodeid,12);
           If Pos(#13,Commandline)>0 then SRec.CLen:=Pos(#13,Commandline)-1
           else SRec.CLen:=Length(Commandline);
           CommandLine:=CommandLine+#13+#10;
           Inc(SRec.CLen,2);
           Move(Commandline[1],SRec.CLine,SRec.CLen);
           AX:=$0900;
           DS:=Seg(SRec);
           BX:=Ofs(SRec);
           Intr($6F,TenRegs);
           If ((Flags and 1)>0)
           then
            begin
               Submit:=AX;
            end
           else Submit:=0;
        end
       else Submit:=$FFFF;
    End;

    Function SetSpool(Printer : Byte; SpoolName : S12; Notification : NotifySet; RDays : Byte): Word;
    { When SetSpool is first called, it merely sets up a "Template" for
      subsequent calls to OpenSpool and CloseSpool. You must be logged into the
      Superstation where you want to spool and be mounted to a printer and a
      drive on that Superstation. SetSpool will determine where the Printer
      (1,2, or 3 for your local LPT1:,LPT2:, or LPT3:) is mounted and a drive
      letter that you are mounted to. }

    VAR
      NT : NotifyTypes;
      DriveTable : DriveArray;
      PrintTable : PrintArray;
      MaxDrive : Integer;
      SSC : Char;
      Pr : String[5];
      SplServer : S12;

    Begin
       If Loaded then with SpoolSettings do
        begin
    { Look at which server printer is mounted on and find out which drives it is
      also mounted to. }
           MaxDrive:=26;
           TenTest:=MountList(DriveTable,PrintTable,MaxDrive);
           If (TenTest=0)
           then
            begin
               SplServer:=PrintTable[Char(Printer+48)].ServerID;
               If ((SplServer='            ')or(SplServer='Local       '))
               then SplServer:=''
               else
                begin
                   Pr:='LPT'+Char(Printer+48)+':';
                   SSC:='A';
                   While not ((SSC>Char(MaxDrive+64))or(DriveTable[SSC].ServerID=SplServer)) do Inc(SSC);
                   If not (DriveTable[SSC].ServerID=SplServer) then SSC:=#0;
                end;
               If ((SSC<>#0)and(SplServer<>''))
               then
                begin
                   UDVC:=Printer;
                   UDVC:=UDVC+(Ord(SSC)-64)shl 4;
                   UCode:=00;
                   If Spoolname<>''
                   then
                    begin
                       While (Pos(' ',Spoolname)>0) do Delete(Spoolname,Pos(' ',Spoolname),1);
                       If (Pos('.',Spoolname)>0) then Delete(Spoolname,Pos('.',Spoolname),1);
                    end;
                   While Length(Spoolname)<11 do Spoolname:=Spoolname+' ';
                   Move(Spoolname[1],SpoolSettings.UFile,11);
                   UNote:=0;
                   If (Start in Notification) then UNote:=UNote or 1;
                   If (Reply in Notification) then UNote:=UNote or 2;
                   If (Completion in Notification) then UNote:=UNote or 4;
                   If (ExplQueue in Notification) then UNote:=UNote or 8;
                   If (NoFF in Notification) then UNote:=UNote or 32;
                   If (IDPage in Notification) then UNote:=UNote or 64;
                   If (QueueTop in Notification) then UNote:=UNote or 2;
                   UDays:=RDays;
                   ULen:=0;
                   UArea:=0;
                   SetSpool:=0;
                   Spooling:=True;
                end
               else SetSpool:=$23FF;
            end
           else SetSpool:=$25FF;
        end
      else SetSpool:=$FFFF;
    End;

    Function OpenSpool(NewSpoolname : S12) : Word;
     {Once SetSpool has "configured" your spool, calls to OpenSpool will
      create a new spoolfile with the optional Newspoolname, or with a name
      automatically set by 10Net if NewSpoolName=''. }

    VAR
       OpenSpoolSet : SpoolBlock;

    Begin
       If Spooling
       then with TenRegs do
        begin
           If NewSpoolname<>''
           then
            begin
               While (Pos(' ',NewSpoolname)>0) do Delete(NewSpoolname,Pos(' ',NewSpoolname),1);
               If (Pos('.',NewSpoolname)>0) then Delete(NewSpoolname,Pos('.',NewSpoolname),1);
            end;
           While Length(NewSpoolname)<11 do NewSpoolname:=NewSpoolname+' ';
           Move(NewSpoolname[1],SpoolSettings.UFile,11);
           Move(SpoolSettings,OpenSpoolSet,Sizeof(SpoolSettings));
           DS:=Seg(OpenSpoolSet);
           DX:=Ofs(OpenSpoolSet);
           AX:=$0E00;
           OpenSpoolSet.UCode:=0;
           Intr($6F,TenRegs);
           If ((Flags and 1)>0)
           then
            begin
               OpenSpool:=AX;
            end
           else OpenSpool:=0;
        end
       else OpenSpool:=$FFFF;
    End;

    Function CloseSpool : Word;
    { Calls to CloseSpool, after a spool has been started through OpenSpool and
      some print has been "sent to the printer", will cause the Spoolfile to
      close and printing to begin if the Print Permit is ON at the location
      where the printer is mounted.
         "Sending print to the printer" is done in the usual manner, from within
      programs, by "Typing and Piping" (TYPE>LPT1 <filename>), by Copying from a
      file to the printer, etc.}

    VAR
       CloseSpoolSet : SpoolBlock;
    Begin
       If Spooling
       then with TenRegs do
        begin
           Move(SpoolSettings,CloseSpoolSet,Sizeof(SpoolSettings));
           DS:=Seg(CloseSpoolSet);
           DX:=Ofs(CloseSpoolSet);
           AX:=$0E00;
           CloseSpoolSet.UCode:=2;
           Intr($6F,TenRegs);
           If ((Flags and 1)>0)
           then
            begin
               CloseSpool:=AX;
            end
           else CloseSpool:=0;
        end
       else CloseSpool:=$FFFF;
    End;

    Function TenConfig(MaxSendRec,MaxRecvRec : Integer; {Size of largest records
                                                         to send/receive}
                       MaxRecs : Integer)   {Maximum number of Records to recv}
                              : Word;
    VAR
       I : Integer;
       RetCode : Word;
    { This function allows the user to dynamically change the size of the
    buffers being used by TBSend and TBReceive to optimize usage.
    MaxSendRec is the size of the largest TBSEND record
    MaxRecvRec is the size of the largest TBRECEIVE record
    MaxRecs is the number of TBReceive records to buffer
    }
    Begin
       If TNTI
       then
        begin
           For I:=1 to MaxReceives do
            begin
               FreeMem(TBD^[I],Sizeof(RcvBlock)*MaxRecvSets);
            end;
           FreeMem(TBD,MaxReceives*4);
           FreeMem(TBR,MaxReceives*Sizeof(RecvRec));
        end;
       RetCode:=0;
       If MaxRecs<1310 then MaxReceives:=MaxRecs
       else RetCode:=RetCode+1;
       If MaxSendRec<=65521 then MaxSendBufferSize:=MaxSendRec
       else RetCode:=RetCode+2;
       If MaxRecvRec<=65521 then MaxRecBuffersize:=MaxRecvRec
       else RetCode:=RetCode+4;
       If MaxRecs>0
       then
        begin
           MaxRecvSets:= MaxRecBufferSize div 457 + 1;
           GetMem(TBR,MaxReceives*Sizeof(RecvRec));
           GetMem(TBD,MaxReceives*4);
           For I:=1 to MaxReceives do
           GetMem(TBD^[I],Sizeof(RcvBlock)*MaxRecvSets);
        end;
       TenConfig:=RetCode;
    End;

    Function SetWait(WaitLimit : Integer): Word;
    { Changes the maximum seconds to wait for receive packets in the same record,
      Defaults to 30 }
    Begin
       If ((WaitLimit>0) and (WaitLimit<3000))
       then
        begin
           MaxRcvWait:=WaitLimit;
           SetWait:=0;
        end
       else SetWait:=$FFFF;
    End;

    Procedure SetUserName(UName : S8);
    {Changes the Username in the Network Table and in the Global variable
      USERNAME}
    VAR
       I : Integer;
    Begin
       If Loaded
       then
        begin
           UserName:=Upcase8(UName);
           Move(UserName[1],ConfigTable^.CT_LName,8);
        end
       else UserName:=Upcase8(UName);
    end;

    { The Unit Initialization Code below locates the Configuration Table Address
    and establishes the buffers necessary to make 10Net function calls. It will
    be called at the beginning of a program to make the tools available
    throughout the program. }

    Begin
       If Loaded
       then with TenRegs do
        begin
    (*      Initially, no space is allocated for Sends and Receives; These
           buffers can be established dynamically with a call to TenConfig.
           TenTest:=TenConfig(MaxSendBufferSize,MaxRecBufferSize,MaxReceives);
           If TenTest<>0 then Writeln('TenConfig Error: ',TenTest);
    *)       AX:=$0300;
           Intr($6F,TenRegs);
           ConfigTable:=Ptr(ES,BX);
           PreConfig:=Ptr(ES,BX-51);
           UserName:='';
           For I10:=1 to 8 do UserName:=UserName+ConfigTable^.CT_LName[I10];
           TNTI:=True;
           Spooling:=False;
        end
       else
        begin
           Writeln('TenTools inititalization Error!');
           Writeln('Netword not Loaded!');
           Spooling:=False;
        end;
    End. { Of TenTools Unit }

[Back to NETWORK SWAG index] [Back to Main SWAG index] [Original]