 Rem File: IO.bas - Cmd*.bas
 Rem $Include: 'dndbbs.inc'

Common Shared Temp.Prompt As String

Function Timeit!
 t1$ = Format$(Now, "hh:mm:ss") ' seconds past midnight
 t1! = CSNG(INT(VAL(MID$(t1$, 1, 2)))) * 3600! + CSNG(INT(VAL(MID$(t1$, 4, 2)))) * 60! + CSNG(INT(VAL(MID$(t1$, 7, 2))))
 Timeit!=t1!
End Function

Function Time.Elapsed(Start.Time!,Wait.Time!)
 Elapsed.Time!=Timeit!-Start.Time!
 If Elapsed.Time!<SFalse Then
    Elapsed.Time!=Elapsed.Time!+86400!
 Endif
 If Elapsed.Time!>=Wait.Time! Then
    Time.Elapsed=True
 Else
    Time.Elapsed=False
 Endif
End Function

Function Config1!(Var)
 On Local Error Goto Error.Trap10a
 Call Read.Message.Record(MessWorkFile9,Var)
 Config1!=UserConfigRecord.UserConfig1
Error.Resume10a:
 Exit Function
Error.Trap10a:
 Resume Error.Resume10a
End Function

Function Config2%(Var)
 On Local Error Goto Error.Trap11
 Call Read.Message.Record(MessWorkFile9,Var+MaxConfigArray1)
 Config2%=UserConfigRecord.UserConfig2
Error.Resume11:
 Exit Function
Error.Trap11:
 Resume Error.Resume11
End Function

Function Config3$(Var)
 On Local Error Goto Error.Trap12
 Call Read.Message.Record(MessWorkFile9,Var+MaxConfigArray1+MaxConfigArray2)
 Var$=Rtrim$(UserConfigRecord.UserConfig3)
 If Right$(Var$,1)=Chr$(1) Then
    Var$=Left$(Var$,Len(Var$)-1)
 Endif
 Config3$=Var$
Error.Resume12:
 Exit Function
Error.Trap12:
 Resume Error.Resume12
End Function

Function DateS$
 DateS$=Format$(Now,"mm-dd-yyyy")
End Function

Function FClock$
 FClock$=Format$(Now,"ddd dd mmm yyyy\, hh:mma/p")
End Function

Function FClock2$
 FClock2$=Format$(Now,"dd mmm yyyy\, hh:mm:ss")
End Function

Function Form$(Var#)
 Form$=Format$(Var#,"#,##0;;"+Chr$(34)+"zero"+Chr$(34))
End Function

Sub Check.Environ(Var)
 If Out2=Nul Then
    Var$=Environ$("MOREPROMPTDEFAULT")
    If Len(Var$) Then
       Select Case Var$
       Case "Y", "YES"
          Yes=-1 : No=0 : Quit=0 : Continuous=0
       Case "N", "NO"
          Yes=0 : No=-1 : Quit=0 : Continuous=0
       Case "Q", "QUIT"
          Yes=0 : No=0 : Quit=-1 : Continuous=0
       Case "C", "CONTINUOUS"
          Yes=0 : No=0 : Quit=0 : Continuous=-1
       Case Else
          Yes=-1 : No=0 : Quit=0 : Continuous=0
       End Select
    Endif
 Endif
End Sub

Sub IO.O
 On Local Error Goto Error.Trap44
 If Environ$("UPPERCASE")<>"" Then
    IO.Upper.Case=-1
 Endif
 If Environ$("TELETYPE")<>"" Then
    IO.Upper.Case=-1
 Endif
 If Lost.Carrier Then
    Exit Sub
 Endif
 If Len(Strng) Then
    If Graphics.On=False Then
       Call Send.ANSI
    Endif
 Endif
 Count=False
 Do
    Call Check.Carrier
    If Lost.Carrier Then
       Exit Sub
    Endif
    Call Check.Break
    Call Keyboard(Var)
    If Break Then
       Exit Do
    Endif
    If Var Then
       Exit Sub
    Endif
    Gosub IO.Wrap
    If Count>Len(Strng) Then
       Exit Do
    Endif
    VarX$=Mid$(Strng,Count,1)
    If IO.Upper.Case Then VarX$=Ucase$(VarX$)
    Call Put.Modem(VarX$)
    Call Scrn(VarX$)
 Loop
 If Carriage.Return=False Then
    If Carriage.Input=False Then
       If Len(Strng)=False Then
          Call Scroll.Return
       Else
	  Call Line.Return
       Endif
    Endif
 Endif
 Strng=Nul
 Carriage.Input=False
 Carriage.Return=False
 Exit Sub
IO.Wrap:
 Count=Count+1
 If User.Linelength>False Then
    Call Get.Cursor(VarC)
    Select Case User.Wordwrap
    Case True
       If VarC>=User.Linelength Then
          If Mid$(Strng,Count,1)=" " Then
             Count=Count+1
          Endif
          If Count<=Len(Strng) Then
             Call Line.Return
             If Mid$(Strng,Count,1)=" " Then
                Count=Count+1
             Endif
          Endif
       Endif
    Case False
       VarW=Instr(Count+1,Strng," ")
       If VarW Then
          VarW$=Mid$(Strng,Count)
          VarW=Instr(2,VarW$," ")
          VarW$=Left$(VarW$,VarW-1)
       Else
          If Mid$(Strng,Count,1)=" " Then
             VarW$=Mid$(Strng,Count)
          Else
             VarW$=Nul
          Endif
       Endif
       If VarC+Len(VarW$)>User.Linelength Then
          If Mid$(Strng,Count,1)=" " Then
             Count=Count+1
          Endif
          Call Line.Return
       Endif
    End Select
 Endif
 Return
Error.Resume44:
 Exit Sub
Error.Trap44:
 Resume Error.Resume44
End Sub

Sub Send.ANSI
 On Local Error Goto Error.Trap99x
 Call Modem.ANSI(4,40,0)
 Call ScreenANSI(4,40,0)
 Select Case Graphics.Off
 Case True
    Call Modem.ANSI(4,37,15)
    Call ScreenANSI(4,37,15)
 Case False
    Color.Code=Color.Code+1
    Avatar.Code=Avatar.Code+1
    Select Case Color.Code
    Case Is<31, Is>35
       Color.Code=31
    End Select
    Select Case Avatar.Code
    Case Is<10, Is>14
       Avatar.Code=10
    End Select
    Call Modem.ANSI(4,Color.Code,Avatar.Code)
    Call ScreenANSI(4,Color.Code,Avatar.Code)
 End Select
Error.Resume99x:
 Exit Sub
Error.Trap99x:
 Resume Error.Resume99x
End Sub

Sub IO.I
 On Local Error Goto Error.Trap45
 If Lost.Carrier Then
    Exit Sub
 Endif
 If Carriage.Return=-2 Then
    Eat$=Nul
 Else
    Call Get.Cursor(VarC)
    If VarC>1 Then
       Call Line.Return
    Endif
 Endif

 ' preemptive warning
 Strng3=Strng
 Var$=Strng
 Call IO.Timing
 Strng=Var$

 ' display input prompt
 Carriage.Input=True
 Prompt$=Strng
 Strng=Strng+Type.Ahead
 Temp.Prompt=Strng
 Call IO.O
 Out2=Type.Ahead
 Type.Ahead=Nul
 Var!=Timeit!

 ' check system messages
 Call Read.Node.Mess(Prompt$)

 ' start i/o loop
 Call Modem.ANSI(4,37,15)
 Call ScreenANSI(4,37,15)
 Do
    Char$=Nul
    Timeout=Timeit!
    Do Until Len(Char$)
       Call Check.Carrier
       If Lost.Carrier Then
	  Exit Sub
       Endif
       Call Check.Break
       Call Get.Modem(False)
       Call Keyboard(Var)
       If Var Then
	  Strng=Nul
	  Call IO.O
	  Exit Sub
       Endif
       If Auto.Break Then
	  Exit Do
       Endif
       If Break Then
	  Exit Do
       Endif
       If Len(Buffer) Then
	  Char$=Left$(Buffer,1)
	  Buffer=Mid$(Buffer,2)
       Endif
       If Time.Elapsed(Var!,1!) Then
          Var!=Timeit!
          Call IO.Timing
          Call Read.Node.Mess(Prompt$)
          If Config2(56)>False Then
             If Time.Elapsed(Timeout,Csng(Config2(56))) Then
                Call Hang.Up(1)
             Endif
          Endif
       Endif
       If Local.Mode Then
          Call Release.Time(1)
       Endif
    Loop
    If Auto.Break Then
       Exit Do
    Endif
    Char=Asc(Char$)
    Select Case Char
    Case 3, 11
       Type.Error=False
       Call Set.Break
    Case 8
       Type.Error=False
       If Len(Out2) Then
	  Out2=Left$(Out2,Len(Out2)-1)
	  Call Back.Space
       Endif
    Case 13
       Type.Error=False
       If Out2=Nul Then
	  If Len(No.Input.Out) Then
	     Out2=No.Input.Out
	     OutY$=Lcase$(No.Input.Out)
             If Len(OutY$) Then
                Mid$(OutY$,1,1)=Ucase$(Mid$(OutY$,1,1))
             Endif
	     If User.Echo=False Then
		Call Put.Modem(OutY$)
	     Endif
	     Call Scrn(OutY$)
	  Endif
       Endif
       Call Line.Return
       Call Get.Row(VarX)
       If VarX<(Max.Row-1) Then
          Call Scrn(Chr$(10))
       Endif
       Exit Do
    Case 32 To 126
       Type.Error=False
       If Out2=Nul Then
          If Upper.Case Then
             If Chat=False Then
                Char$=Ucase$(Char$)
             Endif
          Endif
       Endif
       VarX$=Char$
       If No.Echo=False Then
          If Hidden Then
	     VarX$=Mask$
	  Endif
	  If User.Echo=False Then
	     Call Put.Modem(VarX$)
	  Endif
       Endif
       Out2=Out2+Char$
       ' wordwrap
       If Word.Wrap=False Then
          Call Get.Cursor(VarC)
          Select Case VarC
          Case 1 To User.Linelength-1
             Call Scrn(VarX$)
          Case Else
             Call Line.Return
             Exit Do
          End Select
       Endif
       If Word.Wrap Then
          If No.Echo=False Then
             Call Get.Cursor(VarC)
             Select Case VarC
             Case 1 To User.LineLength-1
                Call Scrn(VarX$)
             Case Else
                VarL=False
                VarW=False
                For VarX=Len(Out2) To 1 Step -1
                   If Mid$(Out2,VarX,1)=" " Then
                      For VarB=1 To VarL
                         Call Back.Space
                      Next
                      Type.Ahead=Mid$(Out2,VarX+1)
                      Out2=Left$(Out2,VarX)
                      VarW=True
                      Exit For
                   Endif
                   VarL=VarL+1
                Next
                If VarW Then
                   Call Line.Return
                Endif
                Exit Do
             End Select
          Endif
       Endif
       If Line.Length>False Then
          If Len(Out2)>=Line.Length Then
             Call Line.Return
             Exit Do
          Endif
       Endif
    Case Else ' garbage
       Type.Error=Type.Error+1
       If Type.Error>=MaxErrors Then
	  Type.Error=False
	  Call Hang.Up(14)
       Endif
    End Select
 Loop
 No.Input=(Out2=Nul)
 No=(Ucase$(Left$(Out2,1))="N")
 Yes=(Ucase$(Left$(Out2,1))="Y")
 Quit=(Ucase$(Left$(Out2,1))="Q")
 Continuous=(Ucase$(Left$(Out2,1))="C")
 Line.Length=False
 No.Echo=False
 No.Input.Out=Nul
 Strng=Nul
Error.Resume45:
 Exit Sub
Error.Trap45:
 Resume Error.Resume45
End Sub

Sub Release.Time(Var)
 On Local Error Goto Error.Trap6a
 If Supported.Call=False Then
    For Var1=1 To Var
       Call Slice.Function
       If (OutregsX.AX And &HFF)=&H80 Then
          Supported.Call=True
          Exit For
       Endif
    Next
 Endif
Error.Resume6a:
 Exit Sub
Error.Trap6a:
 Resume Error.Resume6a
End Sub

Sub Put.Modem(Var$)
 If Local.Mode Then
    Exit Sub
 Endif
 If Lost.Carrier Then
    Exit Sub
 Endif
 For VarX=1 To Len(Var$)
    Var=Asc(Mid$(Var$,VarX,1))
    Do
       Call Driver(3)
       If (OutregsX.AX And &H4000)=&H4000 Then
          InregsX.AX=Var
          Call Driver(1)
          Exit Do
       Endif
    Loop
 Next
 Do
    Call Driver(3)
    If (OutregsX.AX And &H4000)=&H4000 Then
       Exit Do
    Endif
 Loop
End Sub

Sub Get.Modem(Var)
 If Local.Mode Then
    Exit Sub
 Endif
 If Lost.Carrier Then
    Exit Sub
 Endif
 If Fossil.Active Then
    If Fossil.Version=1 Then
       InregsX.AX=&H2000
       InregsX.DX=Port
       Call InterruptX(&H14,InregsX,OutregsX)
       If (OutregsX.AX And &HFF00)=&H0 Then
          Goto End.Input
       Endif
       Exit Sub
    Endif
 Endif
 Call Driver(3)
 If (OutregsX.AX And &H0100)=0 Then
    Exit Sub
 Endif
 Call Driver(2)
End.Input:
 VarX=(OutregsX.AX And &HFF)
 If VarX=3 Or VarX=11 Then
    Call Set.Break
    If Var=False Then
       Buffer=Buffer+Chr$(VarX)
    Endif
 Else
    Buffer=Buffer+Chr$(VarX)
 Endif
End Sub

' send string to modem
Sub Send.Modem(Var$)
 On Local Error Goto Error.Trap55
 If Local.Mode Then
    Exit Sub
 Endif
 Do
    Call Driver(3) ' get line/modem status
    If (OutregsX.AX And &H40)=0 Then ' check ring bit
       Exit Do
    Endif
 Loop
 For VarX=1 To Len(Var$)
    Var=Asc(Mid$(Var$,VarX,1))
    Do
       Call Driver(3) ' get line/modem status
       If (OutregsX.AX And &H4000)=&H4000 Then ' empty buffer
          InregsX.AX=Var
          Call Driver(1) ' send character
          Exit Do
       Endif
    Loop
 Next
 Call Read.Modem
Error.Resume55:
 Exit Sub
Error.Trap55:
 Resume Error.Resume55
End Sub

' read character(s) from modem
Sub Read.Modem
 On Local Error Goto Error.Trap56
 If Local.Mode Then
    Exit Sub
 Endif
 Do
    Call Driver(3) ' get line/modem status
    If (OutregsX.AX And &H0100)=0 Then ' character is available
       Exit Do
    Endif
    Call Driver(2) ' get character
    VarX=(OutregsX.AX And &HFF)
    If VarX>0 Then
       Out2=Out2+Chr$(VarX)
    Endif
 Loop
Error.Resume56:
 Exit Sub
Error.Trap56:
 Resume Error.Resume56
End Sub

' Return Var=-1 if modem offline.
Sub Check.Modem(Var)
 On Local Error Goto Error.Trap46a
 Var=False
 Call Driver(3) ' get line/modem status
 If (OutregsX.AX And &HFF)=&HFF Then ' modem is disconnected
    Var=True
    Exit Sub
 Endif
 If (OutregsX.AX AND &HFF)=&H08 Then ' fossil always sets bit 3
    Var=True
    Exit Sub
 Endif
 If (OutregsX.AX AND &HFF)=&H00 Then ' check non-x00 fossil
    Var=True
    Exit Sub
 Endif
Error.Resume46a:
 Exit Sub
Error.Trap46a:
 Resume Error.Resume46a
End Sub

Sub Check.Break
 On Local Error Goto Error.Trap21
 If Local.Mode=False Then
    If Lost.Carrier Then
       Exit Sub
    Endif
    Call Extended.Driver(16)
    If (OutregsX.AX And 1)=1 Then
       Call Set.Break
    Endif
 Endif
 If Disable.Break=False Then
    DEF SEG = &H40
    X = PEEK(&H71)
    DEF SEG
    IF X = 128 THEN
       Call Control.Break
    END IF
 Endif
Error.Resume21:
 Exit Sub
Error.Trap21:
 Resume Error.Resume21
End Sub

Sub Control.Break
 On Local Error Goto Error.Trap21a
 Call Sleep.Second(1!)
 DEF SEG = &H40
 POKE &H71, &H0
 DEF SEG
 Graphics.Off=True
 Call Send.ANSI
 Call Scrn(Chr$(13)+Chr$(10))
 If Allow.Break Then
    Var$="Enter (B)reak, (C)ancel, (L)ogoff user, (A)bort node: "
 Else
    Var$="Enter (C)ancel, (L)ogoff user, (A)bort node: "
 Endif
 Call Scrn(Var$)
 V$=Inkey$
 Var!=Timeit!
 Do
    V$=Inkey$
    If Time.Elapsed(Var!,30!) Then
       V$="C"
    Endif
    If Len(V$)=2 Then
       If Asc(Right$(V$,1))=0 Then ' imbedded control-break
          DEF SEG = &H40
          POKE &H71, &H0
          DEF SEG
          If Allow.Break Then
             V$="B"
          Else
             V$="C"
          Endif
       Endif
    Endif
    If Len(V$)=1 Then
       Select Case Ucase$(V$)
       Case "B" ' break
          If Allow.Break Then
             Call Scrn("B")
             Call Scrn(Chr$(13)+Chr$(10))
             V$=Inkey$
             Call Set.Break
             Carriage.Input=True
             Strng=Nul
             Call IO.O
             Exit Do
          Endif
       Case "C" ' cancel
          Out2=Nul
          Call Scrn("C")
          Call Scrn(Chr$(13)+Chr$(10))
          V$=Inkey$
          Carriage.Input=True
          Strng=Temp.Prompt
          Call IO.O
          Exit Do
       Case "L" ' logoff
          Call Scrn("L")
          Call Scrn(Chr$(13)+Chr$(10))
          V$=Inkey$
          Carriage.Input=True
          Strng=Nul
          Call IO.O
          Lost.Carrier=-2
          Exit Do
       Case "A" ' abort
          Call Scrn("A")
          Call Scrn(Chr$(13)+Chr$(10))
          V$=Inkey$
          Carriage.Input=True
          Strng=Nul
          Call IO.O
          Lost.Carrier=-2
          Node.Abort=True
          Exit Do
       End Select
    Endif
    Call Release.Time(1)
 Loop
Error.Resume21a:
 Exit Sub
Error.Trap21a:
 Resume Error.Resume21a
End Sub

Sub Set.Break
 On Local Error Goto Error.Trap22
 If Allow.Break Then
    If Auto.Mode Or Chat.Mode Or Follow.Mode Or Monitor.Mode Or Wait.Mode Then
       Auto.Break=True
    Else
       Break=True
    Endif
 Endif
Error.Resume22:
 Exit Sub
Error.Trap22:
 Resume Error.Resume22
End Sub

Sub Check.Carrier
 On Local Error Goto Error.Trap23a
 If Local.Mode Then
    Exit Sub
 Endif
 If Lost.Carrier Then
    Exit Sub
 Endif
 If Mouse.Present Then
    Call MouseDriver
    If Mouse.Button3 Then
       Call Hang.Up(16)
    Endif
 Endif
 Call Driver(3)
 If (OutregsX.AX And &HFF)=&HFF Then
    Call Hang.Up(3)
 Endif
 If (OutregsX.AX And &H80)=False Then
    Call Hang.Up(3)
 Endif
Error.Resume23a:
 Exit Sub
Error.Trap23a:
 Resume Error.Resume23a
End Sub

Sub Sleep.Second(Var!)
 On Local Error Goto Error.Trap5
 Timer.Temp!=Timeit!
 Do
    Call Read.Keyboard(VarX$)
    If Time.Elapsed(Timer.Temp!,Var!) Then
       Exit Do
    Endif
    Call Release.Time(1)
 Loop
Error.Resume5:
 Exit Sub
Error.Trap5:
 Resume Error.Resume5
End Sub

Sub Line.Return
 On Local Error Goto Error.Trap25
 VarX=Break
 Break=False
 If User.Echo=False Then
    Call Put.Modem(Chr$(13))
    If User.Linefeeds=False Then
       Call Put.Modem(Chr$(10))
    Endif
 Endif
 Call Scrn(Chr$(13))
 Break=VarX
Error.Resume25:
 Exit Sub
Error.Trap25:
 Resume Error.Resume25
End Sub

Sub Scroll.Return
 On Local Error Goto Error.Trap26
 VarX=Break
 Break=False
 If User.Echo=False Then
    Call Put.Modem(Chr$(13))
    If User.Linefeeds=False Then
       Call Put.Modem(Chr$(10))
    Endif
 Endif
 Call Scroll.Screen
 Break=VarX
Error.Resume26:
 Exit Sub
Error.Trap26:
 Resume Error.Resume26
End Sub

Sub Back.Space
 On Local Error Goto Error.Trap27
 If Local.Mode=False Then
    If User.Echo=False Then
       Var$=Chr$(8)
       Call Put.Modem(Var$)
       Var$=" "
       Call Put.Modem(Var$)
       Var$=Chr$(8)
       Call Put.Modem(Var$)
    Endif
 Endif
 If Local.ANSI.Color Or Local.Avatar.Color Then
    Call Get.Cursor(VarX)
    If VarX=1 Then
       Call ScreenANSI(2,Max.Row-2,User.LineLength-1)
       Call Put.Screen(" ")
       Call ScreenANSI(2,Max.Row-2,User.LineLength-1)
    Else
       Var$=Chr$(27)+"[D"
       Call Put.Screen(Var$)
       Call Put.Screen(" ")
       Call Put.Screen(Var$)
    Endif
 Else
    If Pos(0)=1 Then
       Locate Max.Row-2,User.LineLength-1,0
       Print " ";
       Locate Max.Row-2,User.LineLength-1,1
    Else
       Locate Csrlin,Pos(0)-1,0
       Print " ";
       Locate Csrlin,Pos(0)-1,1
    Endif
 Endif
Error.Resume27:
 Exit Sub
Error.Trap27:
 Resume Error.Resume27
End Sub

Sub Get.Cursor(Var)
 On Local Error Goto Error.Trap28
 If Local.ANSI.Color Or Local.Avatar.Color Then
    Call VideoInt(3,0)
    Var=(OutregsX.DX And &HFF)+1
    Exit Sub
 Endif
 Var=Pos(0)
Error.Resume28:
 Exit Sub
Error.Trap28:
 Resume Error.Resume28
End Sub

Sub Get.Row(Var)
 On Local Error Goto Error.Trap28a
 If Local.ANSI.Color Or Local.Avatar.Color Then
    Call VideoInt(3,0)
    Var=(OutregsX.DX And &HFF00)/256+1
    Exit Sub
 Endif
 Var=Csrlin
Error.Resume28a:
 Exit Sub
Error.Trap28a:
 Resume Error.Resume28a
End Sub

Sub Scrn(Var$)
 On Local Error Goto Error.Trap33
 If Local.ANSI.Color Or Local.Avatar.Color Then
    Call VideoInt(3,0)
    VarR=Int(OutregsX.DX/&HFF)
    VarC=(OutregsX.DX And &HFF)+1
 Else
    VarR=Csrlin-1
    VarC=Pos(0)
 Endif
 Select Case VarR
 Case Is>Max.Row-2
    Call Scroll.Screen
 Case Max.Row-2
    If VarC>User.LineLength Then
       Call Put.Screen(Chr$(13))
       Call Scroll.Screen
       If Var$=Chr$(13) Then
	  Exit Sub
       Endif
    Endif
    If Var$=Chr$(13) Then
       Call Scroll.Screen
       Exit Sub
    Endif
 End Select
 Call Put.Screen(Var$)
Error.Resume33:
 Exit Sub
Error.Trap33:
 Resume Error.Resume33
End Sub

Sub Scroll.Screen
 On Local Error Goto Error.Trap34
 Var1$=Chr$(13)+Chr$(10)
 If Disk.Log Then
    Call Disk.Output(Var1$)
 Endif
 If Print.Log Then
    Call Print.Output(Var1$)
 Endif
 Call Scrollit(Max.Row-2)
 Locate Max.Row-1,1,1
Error.Resume34:
 Exit Sub
Error.Trap34:
 Resume Error.Resume34
End Sub

Sub Scrollit(Var)
 On Local Error Goto Error.Trap34a
 Call VideoInt(6,Var*256+&H4F)
 Call VideoInt(2,Var*256)
Error.Resume34a:
 Exit Sub
Error.Trap34a:
 Resume Error.Resume34a
End Sub

Sub Scroll.Row(Var)
 On Local Error Goto Error.Trap34b
 Call Put.Screen(Strng)
 Call Scrollit(Max.Row-1)
 Locate Max.Row,1,1
Error.Resume34b:
 Exit Sub
Error.Trap34b:
 Resume Error.Resume34b
End Sub

Sub Local.ANSI(Var1,Var2,Var3)
 On Local Error Goto Error.Trap35
 If Local.ANSI.Color Then
    Call ANSI(Var1,Var2,Var3)
    Exit Sub
 Endif
 If Local.Avatar.Color Then
    Call Avatar(Var1,Var2,Var3)
    Exit Sub
 Endif
 TempD$=Nul
 Select Case Var1
 Case 1
    Call Convert.Color(Var2,True)
 Case 2
    Locate Var2,Var3,1
 Case 3
    Cls
 Case 4
    Call Convert.Color(Var2,False)
 Case 5
    Call Convert.Color(Var2,False)
 End Select
Error.Resume35:
 Exit Sub
Error.Trap35:
 Resume Error.Resume35
End Sub

Sub ScreenANSI(Var1,Var2,Var3)
 On Local Error Goto Error.Trap36
 Call Local.ANSI(Var1,Var2,Var3)
 If Len(TempD$) Then
    Call Put.Screen(TempD$)
 Endif
Error.Resume36:
 Exit Sub
Error.Trap36:
 Resume Error.Resume36
End Sub

Sub Modem.ANSI(Var1,Var2,Var3)
 On Local Error Goto Error.Trap37
 TempD$=Nul
 If Remote.ANSI.Color Then
    Call ANSI(Var1,Var2,Var3)
 Else
    If Remote.Avatar.Color Then
       Call Avatar(Var1,Var2,Var3)
    Endif
 Endif
 If Len(TempD$) Then
    Call Put.Modem(TempD$)
 Endif
Error.Resume37:
 Exit Sub
Error.Trap37:
 Resume Error.Resume37
End Sub

Sub ANSI(VarX,VarY,VarZ)
 On Local Error Goto Error.Trap38
 TempD$=Nul
 Select Case VarX
 Case 1
    TempD$=Chr$(27)+"[0;"+Mid$(Str$(VarY),2)+"m"
 Case 2
    TempD$=Chr$(27)+"["+Mid$(Str$(VarY),2)+";"+Mid$(Str$(VarZ),2)+"H"
 Case 3
    TempD$=Chr$(27)+"[2J"
 Case 4
    TempD$=Chr$(27)+"[1;"+Mid$(Str$(VarY),2)+"m"
 Case 5
    TempD$=Chr$(27)+"["+Mid$(Str$(VarY),2)+"m"
 End Select
Error.Resume38:
 Exit Sub
Error.Trap38:
 Resume Error.Resume38
End Sub

Sub Avatar(VarX,VarY,VarZ)
 On Local Error Goto Error.Trap39
 TempD$=Nul
 Select Case VarX
 Case 1, 4, 5
    TempD$=Chr$(22)+Chr$(1)+Chr$(VarZ)
 Case 2
    TempD$=Chr$(22)+Chr$(8)+Chr$(VarY)+Chr$(VarZ)
 Case 3
    TempD$=Chr$(12)
 End Select
Error.Resume39:
 Exit Sub
Error.Trap39:
 Resume Error.Resume39
End Sub

Sub Put.Screen(Var1$)
 On Local Error Goto Error.Trap40
 If Local.ANSI.Color Or Local.Avatar.Color Then
    For VarX=1 To Len(Var1$)
       VarY=Asc(Mid$(Var1$,VarX,1))
       If VarY=255 Then
          VarY=32
       Endif
       Call StdinInt(6,VarY)
    Next
 Else
    For VarX=1 To Len(Var1$)
       Var2=Asc(Mid$(Var1$,VarX,1))
       Select Case Var2
       Case 10
          Print
       Case 13
          Print;
       Case 255
          Print " ";
       Case Else
          Print Chr$(Var2);
       End Select
    Next
 Endif
 If Disk.Log Then
    Call Disk.Output(Var1$)
 Endif
 If Print.Log Then
    Call Print.Output(Var1$)
 Endif
Error.Resume40:
 Exit Sub
Error.Trap40:
 Resume Error.Resume40
End Sub

Sub Disk.Output(VarX$)
 On Local Error Goto Disk.Error
 Data.Error=False
 If Logged.In=False Then
    Exit Sub
 Endif
 For VarX=1 To Len(VarX$)
    Var2=Asc(Mid$(VarX$,VarX,1))
    Select Case Var2
    Case 10
       Print #DiskFile,""
    Case 13
       Print #DiskFile,"";
    Case Else
       Print #DiskFile,Chr$(Var2);
    End Select
 Next
 Exit Sub
Disk.Exit:
 If Data.Error Then
    Disk.Log=False
    Call Open.Session.Files
 Endif
 Exit Sub
Disk.Error:
 Data.Error=True
 Resume Disk.Exit
End Sub

Sub Print.Output(VarX$)
 On Local Error Goto Print.Error
 Data.Error=False
 If Logged.In=False Then
    Exit Sub
 Endif
 If Instr(VarX$,Chr$(27)) Then
    Exit Sub
 Endif
 For VarX=1 To Len(VarX$)
    Var2=Asc(Mid$(VarX$,VarX,1))
    Select Case Var2
    Case 10
       Print #PrintFile,""
    Case 13
       Print #PrintFile,"";
    Case Else
       If Var2>=32 And Var2<127 Then
          Print #PrintFile,Chr$(Var2);
       Endif
    End Select
 Next
 Exit Sub
Print.Exit:
 If Data.Error Then
    Print.Log=False
    Call Open.Session.Files
 Endif
 Exit Sub
Print.Error:
 Data.Error=True
 Resume Print.Exit
End Sub

Sub Convert.Color(VarX,VarY)
 On Local Error Goto Error.Trap41
 VarF=False
 VarB=False
 Select Case VarX
 Case 30
    VarF=8
 Case 31
    VarF=12
 Case 32
    VarF=10
 Case 33
    VarF=14
 Case 34
    VarF=9
 Case 35
    VarF=13
 Case 36
    VarF=11
 Case 37
    VarF=15
 Case 40
    VarB=8
 Case 41
    VarB=12
 Case 42
    VarB=10
 Case 43
    VarB=14
 Case 44
    VarB=9
 Case 45
    VarB=13
 Case 46
    VarB=11
 Case 47
    VarB=15
 End Select
 If VarF Then
    If VarY Then
       VarF=VarF-8
    Endif
    Color VarF
 Else
    If VarB Then
       VarB=VarB-8
       Color ,VarB
    Endif
 Endif
Error.Resume41:
 Exit Sub
Error.Trap41:
 Resume Error.Resume41
End Sub

Sub Cursor(Var)
 On Local Error Goto Error.Trap42
 If Local.ANSI.Color Or Local.Avatar.Color Then
    Select Case Var
    Case False
       Call VideoInt(3,0)
       Cursor.Position=OutregsX.DX
    Case True
       Call VideoInt(2,Cursor.Position)
    End Select
 Else
    Select Case Var
    Case False
       CursorX=Csrlin
       CursorY=Pos(0)
    Case True
       Locate CursorX,CursorY,1
    End Select
 Endif
 If Var Then
    Var1$=Chr$(13)+Chr$(10)
    If Disk.Log Then
       Call Disk.Output(Var1$)
    Endif
    If Print.Log Then
       Call Print.Output(Var1$)
    Endif
 Endif
Error.Resume42:
 Exit Sub
Error.Trap42:
 Resume Error.Resume42
End Sub

Sub Restore.Color
 On Local Error Goto Error.Trap43
 Call ScreenANSI(1,37,15)
 If Graphics.Off Then
    Call ScreenANSI(4,37,15)
 Else
    Call ScreenANSI(4,Color.Code,Avatar.Code)
 Endif
Error.Resume43:
 Exit Sub
Error.Trap43:
 Resume Error.Resume43
End Sub

Sub Driver(Var)
 On Local Error Goto Error.Trap49
 If Local.Mode Then
    Exit Sub
 Endif
 Select Case Var
 Case 1 ' transmit char
    InregsX.AX=InregsX.AX Or &H0100
 Case 2 ' receive char
    InregsX.AX=&H0200
 Case 3 ' get port status
    InregsX.AX=&H0300
 End Select
 InregsX.DX=Port
 Call InterruptX(&H14,InregsX,OutregsX)
Error.Resume49:
 Exit Sub
Error.Trap49:
 Resume Error.Resume49
End Sub

Sub Extended.Driver(Var)
 On Local Error Goto Error.Trap50
 If Local.Mode Then
    Exit Sub
 Endif
 If Fossil.Active=False Then
    OutregsX.AX=False
    Exit Sub
 Endif
 Select Case Var
 Case 9 ' purge output
    InregsX.AX=&H0900
 Case 10 ' purge input
    InregsX.AX=&H0A00
 Case 13 ' dcd watchdog on
    InregsX.AX=&H1401
 Case 14 ' dcd watchdog off
    InregsX.AX=&H1400
 Case 15 ' flow control
    InregsX.AX=&H0F00
    If Config2(79) Then ' xon/xoff
       InregsX.AX=InregsX.AX Or &H09
    Endif
    If Config2(80) Then ' rts/cts
       InregsX.AX=InregsX.AX Or &H02
    Endif
 Case 16 ' set/check control-c/control-k
    InregsX.AX=&H1001
 Case 17 ' warm reboot
    InregsX.AX=&H1701
 Case 18 ' cold reboot
    InregsX.AX=&H1700
 Case 28 ' activate
    If Fossil.Version=1 Then
       InregsX.AX=&H1C00 ' x00
    Else
       InregsX.AX=&H0400 ' fossil
    Endif
 Case 29 ' deactivate
    If Fossil.Version=1 Then
       InregsX.AX=&H1D00 ' x00
    Else
       InregsX.AX=&H0500 ' fossil
    Endif
 End Select
 InregsX.DX=Port
 Call InterruptX(&H14,InregsX,OutregsX)
Error.Resume50:
 Exit Sub
Error.Trap50:
 Resume Error.Resume50
End Sub

Sub IO.Timing
 On Local Error Goto Error.Trap18
 If User.Index=SFalse Then
    Exit Sub
 Endif
 Var=False
 Select Case UserRecord.ClassType
 Case Is>=AsstDM
    If Config1(3)>SFalse Then
       Var=True
    Endif
 Case Else
    Select Case UserRecord.Level
    Case Is<=1
       If Config1(1)>SFalse Then
	  Var=True
       Endif
    Case Else
       If Config1(2)>SFalse Then
	  Var=True
       Endif
    End Select
 End Select
 If Time.Override>False Then
    Var=True
 Endif
 If UserRecord.TimeLimit>SFalse Then
    Var=True
 Endif
 If UserRecord.TimeLimit<SFalse Then
    Var=False
 Endif
 If Var Then
    If Time.Elapsed(Timeon,Time.Left) Then
       Call Hang.Up(2)
       Exit Sub
    Endif
    If Two.Minutes.Left>=False Then
       If Time.Left>0! Then
          If Time.Elapsed(Timeon,Time.Left-60!) Then
             Gosub Display.One.Minute
             Exit Sub
          Endif
          If Time.Elapsed(Timeon,Time.Left-120!) Then
             Gosub Display.Two.Minutes
             Exit Sub
          Endif
       Endif
    Endif
 Endif
 If Two.Minutes.Left Then
    Exit Sub
 Endif
 Var1!=Csng(UserRecord.FromHour*3600!+UserRecord.FromMin*60!)
 Var2!=Csng(UserRecord.ToHour*3600!+UserRecord.ToMin*60!)
 If Var1!>SFalse Or Var2!>SFalse Then
    If Timeit!<=Var2! Then
       VarZ!=Var2!
       Gosub Check.Warning2
    Endif
 Endif
 If Two.Minutes.Left Then
    Exit Sub
 Endif
 Var2=False
 For VarZ=1 To 6+Special.Names
    Select Case VarZ
    Case 1
       Var1$=Rtrim$(GuestRecord.TownMayorTime)
    Case 2
       Var1$=Rtrim$(GuestRecord.GovernorTime)
    Case 3
       Var1$=Rtrim$(GuestRecord.GuildMasterTime)
    Case 4
       Var1$=Rtrim$(GuestRecord.SysopTime)
    Case 5
       Var1$=Rtrim$(GuestRecord.DMTime)
    Case 6
       Var1$=Rtrim$(GuestRecord.AsstDMTime)
    Case Else
       Var1$=Rtrim$(SpecialUserTime(VarZ-6))
    End Select
    If Var1$<>Nul Then
       FromH=Val(Mid$(Var1$,1,2))
       FromM=Val(Mid$(Var1$,4,2))
       ToH=Val(Mid$(Var1$,7,2))
       ToM=Val(Mid$(Var1$,10,2))
       Var1!=Csng(FromH*3600!+FromM*60!)
       Var2!=Csng(ToH*3600!+ToM*60!)
       If Var1!>SFalse Or Var2!>SFalse Then
          If Timeit!<=Var1! Then
             Select Case VarZ
             Case 1
                If UserRecord.Flags And Special.Char1 Then
                   Exit Sub
                Endif
             Case 2
                If UserRecord.Flags And Special.Char2 Then
                   Exit Sub
                Endif
             Case 3
                If UserRecord.Flags And Special.Char3 Then
                   Exit Sub
                Endif
             Case 4
                If UserRecord.Flags And Special.Char4 Then
                   Exit Sub
                Endif
             Case 5
                If UserRecord.ClassType=DM Then
                   Exit Sub
                Endif
             Case 6
                If UserRecord.ClassType=AsstDM Then
                   Exit Sub
                Endif
             Case Else
                Var2$=Rtrim$(SpecialUserName(VarZ-6))
                If Ucase$(Rtrim$(UserRecord.CodeName))=Var2$ Then
                   Exit Sub
                Endif
             End Select
          Endif
       Endif
    Endif
 Next
 If Var2=False Then
    Exit Sub
 Endif
 For VarZ=1 To 6+Special.Names
    If Two.Minutes.Left Then
       Exit For
    Endif
    Select Case VarZ
    Case 1
       Var1$=Rtrim$(GuestRecord.TownMayorTime)
       Gosub Check.Warning
    Case 2
       Var1$=Rtrim$(GuestRecord.GovernorTime)
       Gosub Check.Warning
    Case 3
       Var1$=Rtrim$(GuestRecord.GuildMasterTime)
       Gosub Check.Warning
    Case 4
       Var1$=Rtrim$(GuestRecord.SysopTime)
       Gosub Check.Warning
    Case 5
       Var1$=Rtrim$(GuestRecord.DMTime)
       Gosub Check.Warning
    Case 6
       Var1$=Rtrim$(GuestRecord.AsstDMTime)
       Gosub Check.Warning
    Case Else
       Var1$=Rtrim$(SpecialUserTime(VarZ-6))
       Gosub Check.Warning
    End Select
 Next
 Exit Sub
Check.Warning:
 FromH=Val(Mid$(Var1$,1,2))
 FromM=Val(Mid$(Var1$,4,2))
 VarZ!=Csng(FromH*3600!+FromM*60!)
Check.Warning2:
 VarX!=VarZ!-60!
 If VarX!<0! Then
    VarX!=VarX!+86400!
 Endif
 If Timeit!>=VarX! Then
    Gosub Display.One.Minute
    Return
 Endif
 VarX!=VarZ!-120!
 If VarX!<0! Then
    VarX!=VarX!+86400!
 Endif
 If Timeit!>=VarX! Then
    Gosub Display.Two.Minutes
 Endif
 Return
Display.One.Minute:
 If Two.Minutes.Left=1 Then
    Two.Minutes.Left=True
    If Logged.In Then
       Strng=Nul
       Call IO.O
       Call Put.Modem(Chr$(7))
       Strng="Less than one minute left!"
       Call IO.O
    Endif
 Endif
 Return
Display.Two.Minutes:
 If Two.Minutes.Left=False Then
    Two.Minutes.Left=1
    If Logged.In Then
       Strng=Nul
       Call IO.O
       Call Put.Modem(Chr$(7))
       Strng="Less than two minutes left!"
       Call IO.O
    Endif
 Endif
 Return
Error.Resume18:
 Exit Sub
Error.Trap18:
 Resume Error.Resume18
End Sub

Sub Hang.Up(Var)
 On Local Error Goto Error.Trap30
 Buffer=Nul
 Func.Buffer=Nul
 Out2=Nul
 Strng=Nul
 Timeon=Timeit!
 Time.Left=180!
 Select Case Var
 Case 1
    OutZ="Connect timeout"
    Time.Left=30!
 Case 2
    OutZ="Time limit exceeded"
    Time.Left=30!
    If Logged.In Then
       Call Record.Time(False)
    Endif
 Case 3
    Lost.Carrier=True
    OutZ="Lost carrier"
 Case 4
    Lost.Carrier=-2
    OutZ="Forced logoff"
 Case 5
    OutZ="Call limit exceeded"
 Case 6
    OutZ="Call time restriction"
 Case 7
    OutZ="Illegal login attempt"
 Case 8
    OutZ="Password verification"
 Case 9
    OutZ="Not resurrected"
 Case 10
    Node.Abort=True
    OutZ="Nondescriptive data files"
 Case 11
    Node.Abort=True
    OutZ="Program task abort"
 Case 12
    OutZ="Disabled login"
 Case 13
    OutZ="Bad bypass login"
 Case 14
    Lost.Carrier=True
    OutZ="Illegal character entry"
 Case 15
    OutZ="Codename in use"
 Case 16
    Node.Abort=True
    OutZ="Node task abort"
 Case 17
    OutZ="Guest exit"
 Case 18
    OutZ="Time restriction"
 Case 19
    OutZ="Bad node access"
 Case 20
    OutZ="Committed suicide"
 Case Else
    OutZ="Unknown logoff"
 End Select
 Graphics.Off=True
 If Lost.Carrier=False Then
    VarX=False
    Strng=Nul
    Call IO.O
    Graphics.Off=False
    Strng="Dndbbs offline at "
    Strng=Strng+Fclock$
    Call IO.O
    Close #HelpFile3
    Open Logoff.Help.FileName For Random Shared As #HelpFile3 Len=HelpRecLen3
    If Lof(HelpFile3)>False Then
       For TempX=Var*2 To Var*2+1
          If TempX>False And TempX<=Lof(HelpFile3)/HelpRecLen3 Then
             Call Read.HelpFile(HelpFile3,TempX)
             Strng=Rtrim$(HelpRecord3.Text)
             Graphics.Off=True
             Call IO.O
             VarX=True
          Endif
       Next
    Endif
    If VarX=False Then
       Graphics.Off=True
       Strng="You are being logged off: reason; "+OutZ+"."
       Call IO.O
    Endif
    Call IO.O
 Endif
 Graphics.Off=False
 Call Logoff.Prompt
 If OutZ<>Nul Then
    If Rtrim$(NodeX)=Nul Then
       OutZ=OutZ+" (Node -)."
    Else
       OutZ=OutZ+" (Node "+NodeX+")."
    Endif
    If Node>False Then
       Call Send.Mess(4,SFalse,SFalse,OutZ)
    Endif
    Call Update.DayFile(OutZ,True,False)
 Endif
Error.Resume30:
 OutZ=Nul
 Lost.Carrier=True
 Security.Guard=False
 Exit Sub
Error.Trap30:
 Resume Error.Resume30
End Sub

Sub Logoff.Prompt
 On Local Error Goto Error.Trap31
 If Lost.Carrier Then
    Exit Sub
 Endif
 If Node.Abort Then
    Exit Sub
 Endif
 If BBS.Mode=False Then
    Graphics.On=True
    Graphics.Off=False
    If Local.Mode=False Then
       Call Modem.ANSI(1,37,7)
    Endif
 Endif
 Line.Length=1
 No.Echo=True
 Carriage.Return=True
 Strng="Press "+Enter$+" to exit the Adventure:"
 Call IO.O
 Graphics.On=False
 Timer.Temp!=Timeit!
 Do Until Time.Elapsed(Timer.Temp!,10!)
    Call Check.Carrier
    If Lost.Carrier Then
       Exit Do
    Endif
    Call Get.Modem(False)
    If Len(Buffer) Then
       Exit Do
    Endif
    Call Read.Keyboard(VarX$)
    If Len(VarX$) Then
       Exit Do
    Endif
 Loop
 If Local.Mode=False Then
    Strng=Nul
    Call IO.O
 Endif
Error.Resume31:
 Exit Sub
Error.Trap31:
 Resume Error.Resume31
End Sub

' Var: -1=dayfile, 0=daylog, 1=lastuser
Sub Update.Dayfile(Var$,Var,Var3)
 On Local Error Goto ErrorTrap26a
 Select Case Var
 Case 0
    If Config2(70) Then
       FileName=Day.Log.FileName
       Call Clean.UpdateFile(1)
    Endif
 Case -1
    If Config2(71) Then
       FileName=Day.File.FileName
       Call Clean.UpdateFile(2)
    Endif
 Case 1
    FileName=LastUser.FileName
    Call Clean.UpdateFile(3)
 End Select
 If User.Index=SFalse Then
    Temp$="(prelogin)"
 Else
    Call Read.Record(UserFile,User.Index)
    Temp$=Lcase$(Rtrim$(UserRecord.CodeName))
    If Temp$=String$(30,0) Then
       Temp$="(invalid)"
    Else
       If Temp$=Nul Then
          Temp$="(unknown)"
       Endif
    Endif
 Endif
 Mid$(Temp$,1,1)=Ucase$(Mid$(Temp$,1,1))
 Mid$(Var$,1,1)=Ucase$(Mid$(Var$,1,1))
 Select Case Var
 Case True
    FileName=Day.File.FileName
    TempX$=DateS$+" "+Format$(Now,"hh:mm:ss")+" "+Temp$+": "+Var$
 Case False
    FileName=Day.Log.FileName
    Select Case Var3
    Case 1
       Temp$="***"+Temp$
    Case 2
       Temp$="**"+Temp$
    Case 3
       Temp$="*"+Temp$
    Case Else
       Temp$="**"+Temp$
    End Select
    TempX$=DateS$+" "+Format$(Now,"hh:mm:ss")+" "+Temp$+": "+Var$
 Case UnTrue
    FileName=LastUser.FileName
    TempX$=DateS$+" "+Var$
 End Select
 If Var<=0 Then
    If Right$(TempX$,1)<>"!" Then
       If Right$(TempX$,1)<>"." Then
          TempX$=TempX$+"."
       Endif
    Endif
 Endif
 Close #DayFile1
 Open FileName For Random Shared As #DayFile1 Len=DayFileRecLen
 Temp!=Lof(DayFile1)/DayFileRecLen+1!
 BufferRecord.Buffer=TempX$
 Call Write.Record(DayFile1,Temp!)
 Close #DayFile1
ErrorResume26a:
 Exit Sub
ErrorTrap26a:
 Resume ErrorResume26a
End Sub

' Var: 1=dndbbs.log, 2=dndbbs.day, 3=lastuser.dat
Sub Clean.UpdateFile(Var)
 On Local Error Goto ErrorTrap20
 Close #DayFile1
 Open FileName For Random Shared As #DayFile1 Len=DayFileRecLen
 If Lof(DayFile1)=0 Then
    Exit Sub
 Endif
 Call Read.Record(DayFile1,1!)
 Temp$=BufferRecord.Buffer
 ' check last date write
 Var$=DateS$
 If Left$(Temp$,10)<>Var$ Then
    ' backup file
    Close #TempFile1
    Select Case Var
    Case 1
       FileName2$=Data.Path1+"dndlog.bak"
    Case 2
       FileName2$=Data.Path1+"dndday.bak"
    Case 3
       FileName2$=Data.Path1+"lastuser.bak"
    End Select
    Open FileName2$ For Append Shared As #TempFile1
    For Var2=1 To Lof(DayFile1)/DayFileRecLen
       Get #DayFile1,Var2,BufferRecord
       Var$=Rtrim$(BufferRecord.Buffer)
       Print #TempFile1,Var$
    Next
    Close #TempFile1
    ' kill/reopen file
    Close #DayFile1
    Kill FileName
    Open FileName For Random Shared As #DayFile1 Len=DayFileRecLen
 Endif
ErrorResume20:
 Exit Sub
ErrorTrap20:
 Resume ErrorResume20
End Sub

' Var1 = message type
' Var2! = User.Index
' Var3! = Room.Number
' Var1$ = Message
Sub Send.Mess(Var1,Var2!,Var3!,Var1$)
 On Local Error Goto ErrorTrap15
 Temp$=String$(MaxNodes+1,"0")
 For Temp4=False To MaxNodes
    VarX3=Temp4+1
    Call Read.Message.Record(MessWorkFile1,VarX3)
    HiddenMess=False
    If Temp4=Node Then
       HiddenMess=True
       If Var1=7 Then
          Strng="Whisper sent."
          Call IO.O
       Endif
       If Echo Then
          Select Case Var1
          Case 1, 2, 3, 6
             Strng="Message sent."
             Call IO.O
          Case 10, 11
             Strng="Telepathic message sent."
             Call IO.O
          Case 12, 14
             Strng="Program abort sent."
             Call IO.O
          Case 32, 33
             Strng="Program shutdown sent."
             Call IO.O
          End Select
       Endif
    Endif
    If Var2!>SFalse And MessWorkRecord1.UserIndex<>Var2! Then
       HiddenMess=True
    Endif
    If Var3!>SFalse And MessWorkRecord1.RoomNumber<>Var3! Then
       HiddenMess=True
    Endif
    If Var3!<SFalse Then
       HiddenMess=True
       If MessWorkRecord1.RoomNumber=Room Then
          HiddenMess=False
       Endif
       For Temp5=1 To MaxDirections
          If RoomRecord.Direct(Temp5)>False Then
             If MessWorkRecord1.RoomNumber=RoomRecord.Direct(Temp5) Then
                HiddenMess=False
                Exit For
             Endif
          Endif
       Next
    Endif
    If Temp4<>Node Then
       If Chat.Mode Then
          If MessWorkRecord1.Chatting=False Then
             HiddenMess=True
          Endif
       Endif
       If MessWorkRecord1.Monitor Then
          HiddenMess=True
       Endif
    Endif
    If MessWorkRecord1.UserIndex=SFalse Then
       If MessWorkRecord1.RoomNumber=SFalse Then
          HiddenMess=True
       Endif
    Endif
    If HiddenMess Then
       Mid$(Temp$,Temp4+1,1)="1"
    Endif
    If Temp4<>Node Then
       Select Case Var1
       Case 1, 2, 3, 6, 7, 10, 11, 25, 26
          VarX3=Temp4+1
          Call Read.Message.Record(MessWorkFile1,VarX3)
          If Mid$(MessWorkRecord1.ReceiveFlags,Node+1,1)="0" Then
             Mid$(Temp$,Temp4+1,1)="1"
          Endif
          VarX2=Node+1
          Call Read.Message.Record(MessWorkFile1,VarX2)
          If Mid$(MessWorkRecord1.SendFlags,Temp4+1,1)="0" Then
             Mid$(Temp$,Temp4+1,1)="1"
          Endif
       End Select
    Endif
 Next
 Mid$(Temp$,Node+1,1)="1"
 If Temp$=String$(MaxNodes+1,"1") Then
    Select Case Var1
    Case 1, 2, 3, 6, 7, 10, 11, 26
       Strng="Nobody hears you!"
       Call IO.O
    End Select
 Endif
 If Echo=False Then
    Select Case Var1
    Case 1, 2, 3, 26
       Mid$(Temp$,Node+1,1)="0"
    End Select
 Endif
 For Temp4=False To MaxNodes
    If Temp4<>Node Then
       VarX3=Temp4+1
       Call Read.Message.Record(MessWorkFile1,VarX3)
       If MessWorkRecord1.Monitor Then
          Select Case Var1
          Case 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 20, 25, 26, 32
             Mid$(Temp$,Temp4+1,1)="0"
          Case 8
             If MessWorkRecord1.RoomNumber=Room Then
                Mid$(Temp$,Temp4+1,1)="0"
             Endif
          Case 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 33, 37, 38, 39, 40
             If MessWorkRecord1.UserIndex=Var2! Then
                Mid$(Temp$,Temp4+1,1)="0"
             Endif
          End Select
       Endif
    Endif
 Next
 If Var1=25 Then ' group message
    For Var!=1! To Lof(MessWorkFile2)/MessWorkRecLen2
       Call Read.Record(MessWorkFile2,Var!)
       If MessWorkRecord2.Flags=String$(MaxNodes+1,"1") Then
          Exit For
       Endif
    Next
 Else
    For Var!=1! To Lof(MessWorkFile2)/MessWorkRecLen2
       Call Read.Record(MessWorkFile2,Var!)
       If MessWorkRecord2.Flags=String$(MaxNodes+1,"1") Then
          Exit For
       Endif
       VarX!=Csng(Config2(132))
       If VarX!>SFalse Then
          If Time.Elapsed(MessWorkRecord2.MessageTime,VarX!) Then
             Exit For
          Endif
       Endif
    Next
    If Var!>Csng(Config2(133)) Then
       Exit Sub
    Endif
 Endif
 Strng=UserRecord.CodeName
 MessWorkRecord2.Flags=Temp$
 MessWorkRecord2.Message=Var1$
 MessWorkRecord2.MessageTime=Timeit!
 MessWorkRecord2.MessageType=Var1
 MessWorkRecord2.Node=Node
 MessWorkRecord2.RoomNumber=Room
 MessWorkRecord2.UserIndex=User.Index
 MessWorkRecord2.UserName=Strng
 If Var1=25 Then ' group message
    MessWorkRecord2.Message2=Str$(TempX)+TempA$ ' group line+time
 Else
    MessWorkRecord2.Message2=Out4
 Endif
 Call Write.Record(MessWorkFile2,Var!)
ErrorResume15:
 Exit Sub
ErrorTrap15:
 Resume ErrorResume15
End Sub

Sub Read.Keyboard(Var$)
 On Local Error Goto Error.Trap32
 Var$=Inkey$
 If Len(Var$) Then
    Exit Sub
 Endif
 If Logged.In=False Then
    Exit Sub
 Endif
 If Local.Mode=False Then
    Exit Sub
 Endif
 Select Case Asc(Right$(Var$,1))
 Case 79, 147 ' end/control-delete
    Exit Sub
 Case 71 ' home
    Exit Sub
 Case 83 ' delete
    Exit Sub
 Case 82 ' insert
    Exit Sub
 Case 146 ' ctrl-insert
    Exit Sub
 Case 76, 143 ' keypad-5/control-keypad-5
    Exit Sub
 Case 32 ' Alt-D
    Call Flag.Toggles(7)
    If Disk.Log Then
       Strng="Disk log open."
    Else
       Strng="Disk log closed."
    Endif
    Call IO.O
    Exit Sub
 Case 25 ' Alt-P
    Call Flag.Toggles(8)
    If Disk.Log Then
       Strng="Print log open."
    Else
       Strng="Print log closed."
    Endif
    Call IO.O
    Exit Sub
 Case 17 ' Alt-W
    If Print.Log=False Then
       Strng=Nul
       Call IO.O
       Strng="Print log not open."
       Call IO.O
       Exit Sub
    Endif
    Call Print.Screen
    Strng="Screen print."
    Call IO.O
    Exit Sub
 Case 45 ' Alt-X
    If Disk.Log=False Then
       Strng=Nul
       Call IO.O
       Strng="Disk log not open."
       Call IO.O
       Exit Sub
    Endif
    Call Print.LogFile
    Strng="Screen dump."
    Call IO.O
    Exit Sub
 Case 44 ' Alt-Z
    Debug.Mode=Not Debug.Mode
    Call IO.O
    If Debug.Mode Then
       Strng="Debug mode on."
    Else
       Strng="Debug mode off."
    Endif
    Call IO.O
    Exit Sub
 Case 59 To 68 ' F1 To F10
    If Chat Then
       Exit Sub
    Endif
 Case 94 To 103 ' Ctrl-F1 To Ctrl-F10
    If Chat Then
       Exit Sub
    Endif
 Case 104 To 113 ' Alt-F1 To Alt-F10
    If Chat Then
       Exit Sub
    Endif
 Case 120 To 131 ' Alt-1 To Alt-0, Alt--, Alt-=
    If Chat Then
       Exit Sub
    Endif
 Case 133, 137, 139 ' F11, Ctrl-F11, Alt-F11
    If Chat Then
       Exit Sub
    Endif
 End Select
 If Normal.User Then
    Exit Sub
 Endif
 Var$=Nul
Error.Resume32:
 Exit Sub
Error.Trap32:
 Resume Error.Resume32
End Sub

Sub Print.Screen
 On Local Error Goto Error.Trap32x
 Print #PrintFile,Chr$(13)+Chr$(10);
 For Var1=1 To Max.Row-1
    For Var2=1 To User.LineLength-1
       TempZ1=Screen(Var1,Var2) ' char
       Print #PrintFile,Chr$(TempZ1);
    Next
    Print #PrintFile,Chr$(13)+Chr$(10);
 Next
 Exit Sub
Error.Resume32x:
 Exit Sub
Error.Trap32x:
 Print.Log=False
 Resume Error.Resume32x
End Sub

Sub Print.LogFile
 On Local Error Goto Error.Trap32z
 Print #DiskFile,Chr$(13)+Chr$(10);
 For Var1=1 To Max.Row-1
    For Var2=1 To User.LineLength-1
       TempZ1=Screen(Var1,Var2) ' char
       Print #DiskFile,Chr$(TempZ1);
    Next
    Print #DiskFile,Chr$(13)+Chr$(10);
 Next
 Exit Sub
Error.Resume32z:
 Exit Sub
Error.Trap32z:
 Disk.Log=False
 Resume Error.Resume32z
End Sub

Sub MouseDriver
 On Local Error Goto Error.Trap14
 Mouse.Button2=False
 Call Mouse.Function(5,1)
 If (OutregsX.AX AND 2)=2 Then
    If OutregsX.BX>False Then
       Mouse.Button2=True
       Exit Sub
    Endif
 Endif
 Mouse.Button3=False
 Call Mouse.Function(5,2)
 If (OutregsX.AX AND 4)=4 Then
    If OutregsX.BX>False Then
       Mouse.Button3=True
       Exit Sub
    Endif
 Endif
 Mouse.Button=False
 Call Mouse.Function(5,0)
 If (OutregsX.AX AND 1)=1 Then
    If OutregsX.BX>False Then
       Mouse.Button=True
       Mouse.Row=Int((OutregsX.DX)/8+1)
       Mouse.Column=Int((OutregsX.CX)/8+1)
       Exit Sub
    Endif
 Endif
 Call Mouse.Function(3,0)
 Var2=Int((OutregsX.CX)/8+1)
 Var3=Int((OutregsX.DX)/8+1)
 Mouse.Row=False
 Mouse.Column=False
 If Var3<>Mouse.X Or Var2<>Mouse.Y Then
    Mouse.X=Var3
    Mouse.Y=Var2
    Mouse.Row=Mouse.X
    Mouse.Column=Mouse.Y
 Endif
Error.Resume14:
 Exit Sub
Error.Trap14:
 Resume Error.Resume14
End Sub

Sub Keyboard(Var1)
 On Local Error Goto Error.Trap24
 Call Read.Keyboard(VarX$)
 Var1=False
 VarQ=False
 Select Case Len(VarX$)
 Case 0
    Exit Sub
 Case 1
    Var=Asc(VarX$)
    Select Case Var
    Case 8, 13, 32 To 127
       Buffer=Buffer+VarX$
    Case 3,  11
       Call Set.Break
    Case 27
       If Chat Then
          Break=True
	  Chat=False
       Endif
    End Select
 Case 2
    VarZ=Asc(Right$(VarX$,1))
    Select Case VarZ
    Case 71 ' home
       Call Shell.Editor(1) ' edit.exe
    Case 82 ' insert
       Call Shell.Editor(2) ' dndedit.exe
    Case 83 ' delete
       Call Shell.Editor(3) ' dndcnfg.exe
    Case 146 ' ctrl-insert
       Call Shell.Editor(4) ' dndsic.exe
    Case 76 ' keypad-5
       Call Shell.Editor(5) ' edit.com
    Case 143 ' control-keypad-5
       Call Shell.Editor(6) ' qbasic.exe
    Case 79 ' end
       Color 7, 0
       VarX=True
       If Chat.Mode And Last.Command.Number=1 Then ' /auto
          VarX=False
       Endif
       If Chat.Mode And Last.Command.Number=14 Then ' /wait
          VarX=False
       Endif
       If Auto.Mode Or Follow.Mode Or Wait.Mode Or Monitor.Mode Then
          VarX=False
       Endif
       If VarX Then ' /chat
          Locate Max.Row-1,1,1
          Print
       Endif
       Call Hang.Up(4)
       Var1=True
    Case 147 ' control-delete
       If Logged.In Then ' lockout user
          If User.Index>SFalse Then
             Close #TempFile2
             Open DND.Path+"delete.log" For Append Shared As #TempFile2
             Print #TempFile2,Lcase$(Rtrim$(UserRecord.CodeName))
             Print #TempFile2,Fclock$+" ("+DateS$+")"
             Print #TempFile2,"Locked out."
             Close #TempFile2
             Strng=Nul
             Call IO.O
             Graphics.Off=True
             Strng="User locked out: "+Fclock$+"."
             Call IO.O
             Graphics.Off=False
             Call Hang.Up(4)
             Var1=True
          Endif
       Endif
    Case 59 To 68 ' F1 To F10
       VarQ=VarZ-58
    Case 94 To 103 ' Ctrl-F1 To Ctrl-F10
       VarQ=VarZ-93
    Case 104 To 113 ' Alt-F1 To Alt-F10
       VarQ=VarZ-103
    Case 120 To 131 ' Alt-1 To Alt-0, Alt--, Alt-=
       VarQ=VarZ-119
    Case 133, 137, 139 ' F11, Ctrl-F11, Alt-F11
       VarQ=11
    Case 134, 138, 140 ' F12, Ctrl-F12, Alt-F12
       VarQ=12
    Case Else
       If Local.Mode=False Then
	  Func.Buffer=Right$(VarX$,1)
	  Var1=True
       Endif
    End Select
 End Select

 ' display chat macro
 If VarQ Then
    If Chat Then
       Strng=Rtrim$(Temp.ArrayS(VarQ))
       If Len(Strng) Then
          If Left$(Strng,1)=Chr$(34) Then ' quote
             If Right$(Strng,1)=Chr$(34) Then
                Strng=Left$(Strng,Len(Strng)-1)
                Strng=Mid$(Strng,2)
             Endif
          Endif
          Carriage.Input=True
          Call Convert.String
          Call Convert.ANSI(True,VarQ,VarR)
          Carriage.Input=True
          Graphics.On=True
          Call IO.O
          Graphics.On=False
          Call Modem.ANSI(1,40,0) ' reset background
          Call ScreenANSI(1,40,0)
          Call Modem.ANSI(4,37,15) ' set foreground to white
          Call ScreenANSI(4,37,15)
       Endif
    Endif
 Endif
Error.Resume24:
 Exit Sub
Error.Trap24:
 Resume Error.Resume24
End Sub

Sub Shell.Editor(Var)
 On Local Error Goto Error.Trap11z2
 Select Case Var
 Case 1
    Filename=Dnd.Path+"edit.exe"
 Case 2
    Filename=Dnd.Path+"dndedit.exe"
 Case 3
    Filename=Dnd.Path+"dndcnfg.exe"
 Case 4
    Filename=Dnd.Path+"dndsic.exe"
 Case 5
    Filename=Inline.Filename1
 Case 6
    Filename=Inline.Filename2
 End Select
 If FileName="" Then
    Exit Sub
 Endif
 If Dir$(FileName)="" Then
    Exit Sub
 Endif
 Strng=Nul
 Call Modem.ANSI(4,37,15)
 Call ScreenANSI(4,37,15)
 Call IO.O
 Strng="Sysop is using editor.."
 Call IO.O
 Call Save.Status.Line(Var$)
 Call Close.Files
 If Debug.Mode Then
    Color 7,0
    Print "Shelling: "+Ucase$(Filename)
    Print "  (error here then use Shroom)"
 Endif
 Shell Filename
 Call Open.Shell.Files
 Strng="Now returning from editor.."
 Call IO.O
 Temp$=Var$
 If Rtrim$(Temp$)="" Then
    Temp$="Dndbbs> "+Fclock$
    Temp$=Temp$+Space$(79-Len(Temp$))
 Endif
 Call Display.Status.Line(True)
 Call Modem.ANSI(4,37,15)
 Call ScreenANSI(4,37,15)
 If Auto.Mode Or Chat.Mode Or Follow.Mode Or Monitor.Mode Or Wait.Mode Then
    Strng=Nul
 Else
    Strng=Strng3
 Endif
 Carriage.Return=True
 Call IO.O
Error.Resume11z2:
 Exit Sub
Error.Trap11z2:
 Resume Error.Resume11z2
End Sub

' store statusline
Sub Save.Status.Line(Var$)
 On Local Error Goto Error.Trap11z
 Var$=Nul
 Var1=Max.Row
 For Var2=1 To 79
    Var$=Var$+Chr$(Screen(Var1,Var2)) ' char
 Next
Error.Resume11z:
 Exit Sub
Error.Trap11z:
 Resume Error.Resume11z
End Sub

Sub Open.Session.Files
 On Local Error Goto Error.Trap11a
 Close #DiskFile
 If Disk.Log Then
    Filename=DND.Path+Config3(81)+NodeX+File.Extension1
    Open Filename For Append Shared As #DiskFile
 Else
    FileName=Data.Path3+Config3(69)+NodeX+File.Extension1
    Open Filename For Random Shared As #DiskFile
 Endif
 Close #PrintFile
 If Print.Log Then
    Filename=Config3(82)
    Open Filename For Output As #PrintFile
 Else
    FileName=Data.Path3+Config3(69)+NodeX+File.Extension1
    Open Filename For Random Shared As #PrintFile
 Endif
Error.Resume11a:
 Exit Sub
Error.Trap11a:
 Resume Error.Resume11a
End Sub

Sub Flag.Toggles(Var)
 On Local Error Goto Error.Trap24a
 Select Case Var
 Case 1
    User.Linefeeds=Not User.Linefeeds
    If User.Linefeeds=False Then
       Strng="Linefeeds on."
    Else
       Strng="Linefeeds off."
    Endif
    Call IO.O
 Case 2
    Echo=Not Echo
    If Echo=False Then
       Strng="Message echo on."
    Else
       Strng="Message echo off."
    Endif
    Call IO.O
 Case 3
    User.Echo=Not User.Echo
    If User.Echo=False Then
       Strng="Echo duplex on."
    Else
       Strng="Echo duplex off."
    Endif
    Call IO.O
 Case 4
    User.WordWrap=Not User.WordWrap
    If User.WordWrap=False Then
       Strng="Wordwrap on."
    Else
       Strng="Wordwrap off."
    Endif
    Call IO.O
 Case 5
    Sorting=Sorting+1
    Select Case Sorting
    Case 1
       Strng="Inventory charges sorting on."
    Case 2
       Strng="Inventory plus sorting on."
    Case Else
       Sorting=False
       Strng="Inventory sorting off."
    End Select
    Call IO.O
 Case 6
    Debug.Mode=Not Debug.Mode
    If Debug.Mode Then
       Strng="DEBUG mode on."
    Else
       Strng="DEBUG mode off."
    Endif
    Call IO.O
 Case 7
    Disk.Log=Not Disk.Log
    Call Open.Session.Files
 Case 8
    Print.Log=Not Print.Log
    Call Open.Session.Files
 End Select
Error.Resume24a:
 Exit Sub
Error.Trap24a:
 Resume Error.Resume24a
End Sub

Sub Record.Time(Var)
 On Local Error Goto ErrorTrp55a
 If Var Then
    If UserRecord.TimeLimit>SFalse Then
       Var!=Timeit!-Timeon
       If Var!<SFalse Then
          Var!=Var!+86400!
       Endif
       UserRecord.TimeUsed=UserRecord.TimeUsed+Var!
    Endif
 Else
    UserRecord.TimeUsed=Csng(UserRecord.TimeLimit*60!)
 Endif
' UserRecord.TimesLogon=UserRecord.TimesLogon+1#
 Call Write.Record(UserFile,User.Index)
ErrorRsm55a:
 Exit Sub
ErrorTrp55a:
 Resume ErrorRsm55a
End Sub

Sub Valid(Var$,Var)
 On Local Error Goto Error.Trap27a
 If Len(Var$)/2<>Len(Var$)\2 Then
    Var$=Var$+" "
 Endif
 If Var/2<>Var\2 Then
    Var=Var+1
 Endif
 Var$=Left$(Var$,Var)
 Var$=Var$+Space$(Var-Len(Var$))
 For Var1=1 To Var
    Var2=Asc(Mid$(Var$,Var1,1))
    If Var2<32 Or Var2>127 Then
       Var$=Nul
       Exit Sub
    Endif
 Next
Error.Resume27a:
 Exit Sub
Error.Trap27a:
 Resume Error.Resume27a
End Sub

Sub Valid.Name(Var$)
 On Local Error Goto Error.Trap58
 TempA=True
 Select Case Lcase$(Rtrim$(Var$))
 Case "login", "logoff", "relogin"
    TempA=False
 Case "deleted", "offline", "enter"
    TempA=False
 Case "dead", "null", "range error"
    TempA=False
 Case Deleted$, Offline$, Enter$
    TempA=False
 Case Dead$, None$, Range$
    TempA=False
 End Select
Error.Resume58:
 Exit Sub
Error.Trap58:
 Resume Error.Resume58
End Sub

' adds dndpack detection 10/10/2024.
Sub Read.Node.Mess(VarX$)
 On Local Error Goto ErrorTrap13x
 FilenameX$=DND.Path+"NODEEXIT.OUT"
 If Dir$(FilenameX$)<>"" Then
    Color 7, 0
    Locate Max.Row-1,1,1
    Print
    Call Hang.Up(4)
    Exit Sub
 Endif
 Graphics.Off=True
 For Var!=1 To Lof(MessWorkFile2)/MessWorkRecLen2
    Call Read.Record(MessWorkFile2,Var!)
    VarX=False
    If Mid$(MessWorkRecord2.Flags,Node+1,1)="0" Then
       Select Case MessWorkRecord2.MessageType
       Case 12, 14, 30, 31
          VarX=True
          Strng=" aborted program!"
       Case 32, 33
          VarX=True
          Strng=" shutdown program!"
       Case 35
          VarX=True
          Strng=MessWorkRecord2.Message
       End Select
       If VarX Then
          Mid$(MessWorkRecord2.Flags,Node+1,1)="1"
          Call Write.Record(MessWorkFile2,Var!)
          Exit For
       Endif
    Endif
 Next
 If VarX=False Then
    Exit Sub
 Endif
 If MessWorkRecord2.Node=False Then
    Out3="P##"
 Else
    If Brief.Messages Then
       Select Case MessWorkRecord2.Node
       Case 1 To 10 ' 0-9
          Out3="P#"+Mid$(Str$(MessWorkRecord2.Node-1),2)
       Case 11 To 36 ' A-Z
          Out3="P#"+Chr$(MessWorkRecord2.Node+54)
       Case 37 To 126 ' 10-99
          Out3="P#"+Mid$(Str$(MessWorkRecord2.Node-27),2)
       End Select
    Else
       Out3=MessWorkRecord2.UserName
       Out3=Rtrim$(Out3)
       Out3=Lcase$(Out3)
       Mid$(Out3,1,1)=Ucase$(Mid$(Out3,1,1))
    Endif
 Endif
 Strng=Out3+Strng
 Mid$(Strng,1,1)=Ucase$(Mid$(Strng,1,1))
 Select Case MessWorkRecord2.MessageType
 Case 12, 14
    Call IO.O
    'If Node>False Then
       Call Hang.Up(11)
    'Endif
 Case 30 ' dndpack suspend mode on
    VarX2=Node+1
    Call Read.Message.Record(MessWorkFile1,VarX2)
    MessWorkRecord1.SuspendNode=True
    Call Write.Message.Record(MessWorkFile1,VarX2)
    Suspend.Node=True
    Call Hang.Up(3)
 Case 31 ' dndpack suspend mode off
    VarX2=Node+1
    Call Read.Message.Record(MessWorkFile1,VarX2)
    MessWorkRecord1.SuspendNode=False
    Call Write.Message.Record(MessWorkFile1,VarX2)
    Suspend.Node=False
 Case 32, 33 ' shut down node
    Call IO.O
    'If Node>False Then
       Color 7, 0
       Locate Max.Row-1,1,1
       Print
       Call Hang.Up(4)
    'Endif
 Case 35 ' shut down message
    Var$=Strng
    Strng=Nul
    Call IO.O
    Strng=Var$
    Call IO.O
    Graphics.Off=False
    Carriage.Input=True
    Strng=VarX$
    Call IO.O
    Out2=Nul
 End Select
ErrorResume13x:
 Exit Sub
ErrorTrap13x:
 Resume ErrorResume13x
End Sub

Sub More.Prompt
 On Local Error Goto Error.Trap51
 VarX=Allow.Break
 Allow.Break=False
 Auto.Break=False
 Break=False
 Buffer=Nul
 Line.Length=1
 No.Echo=True
 Var=Graphics.Off
 Graphics.Off=False
 Type.Ahead=Nul
 Out2=Nul
 If Environ$("MOREPROMPT")<>"" Then
    Strng=Environ$("MOREPROMPT")
    If Left$(Strng,1)=Chr$(34) Then
       If Right$(Strng,1)=Chr$(34) Then
          Strng=Left$(Strng,Len(Strng)-1)
          Strng=Mid$(Strng,2)
       Endif
    Endif
    Word.Wrap=-1
    Call IO.I
    Word.Wrap=0
 Else
    Strng=More$
    Call IO.I
 Endif
 Call Check.Environ(-1)
 Graphics.Off=Var
 Allow.Break=VarX
Error.Resume51:
 Exit Sub
Error.Trap51:
 Resume Error.Resume51
End Sub

' Var1$ =
'  -1 ignore convert string
'  -2 ignore ; and convert
'  -3 display convert ansi w/ color override
'  .ans process ansi more prompt

Sub Out.File(Var$,Var1$)
 On Local Error Goto ErrorTrap23x
 If Dir$(Var$)=Nul Then
    If Local.Mode And Debug.Mode Then
       Carriage.Return=False
       Strng="Filename: "+Var$+" <not found>"
       Call IO.O
    Endif
    Exit Sub
 Endif
 If Local.Mode And Debug.Mode Then
    Carriage.Return=False
    Var=Var+1
    Strng="Filename: "+Var$
    Call IO.O
 Endif
 Graphics.Off=False
 If Environ$("FILELISTHEADER")<>"" Then
    Strng=Environ$("FILELISTHEADER")
    If Left$(Strng,1)=Chr$(34) Then
       If Right$(Strng,1)=Chr$(34) Then
          Strng=Left$(Strng,Len(Strng)-1)
          Strng=Mid$(Strng,2)
       Endif
    Endif
    Select Case Ucase$(Strng)
    Case "OFF","FALSE","0"
       Eat$=Nul
    Case Else
       Call IO.O
       Var=Var+1
    End Select
 Else
    Strng="File list. "
    If Local.Mode Then
       Var2$="Press <ctrl-break>/<ctrl-c> to interrupt."
    Else
       Var2$="Press <control-c>/<control-k> to interrupt."
    Endif
    Strng=Strng+Var2$
    Call IO.O
    Var=Var+1
 Endif
 Allow.Break=True
 Break=False
 Continuous=False
 Graphics.Off=True
 VarQ=False
 VarR=False
 Close #TempFile1
 Open Var$ For Input Shared As #TempFile1
 Call Modem.ANSI(4,37,15)
 Call ScreenANSI(4,37,15)
 Do While Lost.Carrier=False
    Allow.Break=True
    If Eof(TempFile1) Then
       Exit Do
    Endif
    Line Input #TempFile1,Strng
    If Var1$ = "-3" Then ' casino
       Eat$ = Nul
    Else
       If Lcase$(Strng)="[eof]" Then
          Exit Do
       Endif
    Endif
    VarZ=-1
    If Left$(Strng,1)=";" Then ' comment
       If Var1$="-2" Or Var1$="-3" Then
          VarZ=-1
       Else
          VarZ=0
       Endif
    Endif
    If VarZ Then
       If Len(Strng) Then
          Var2$=ANSIPrefixChar
          If Len(Var2$) Then
             For VarZ2=1 To 5
                Var3$=Var2$+"M"+Ltrim$(Str$(VarZ2))
                If Instr(Ucase$(Strng),Var3$) Then
                   Var=False
                   Exit For
                Endif
             Next
             Var3$=Var2$+"MO"
             If Instr(Ucase$(Strng),Var3$) Then
                Var=False
             Endif
             Var3$=Var2$+"CS"
             If Instr(Ucase$(Strng),Var3$) Then
                Var=False
             Endif
          Endif
       Endif
       If Var1$="-3" Then ' fixed for casino 04/07/2020
          Call Convert.String
          Call Convert.ANSI(True,VarQ,VarR)
          If No Or Quit Then ' 11-15-2018
             Exit Do
          Endif
       Else
          If Var1$="-2" Then
             Eat$=Nul
          Else
             If Var1$="-1" Then
                Call Convert.ANSI(True,VarQ,VarR)
                If No Or Quit Then ' 11-15-2018
                   Exit Do
                Endif
             Else
                Call Convert.String
                Call Convert.ANSI(False,VarQ,VarR)
                If No Or Quit Then ' 11-15-2018
                   Exit Do
                Endif
             Endif
          Endif
       Endif
       Strng2=Strng
       Graphics.On=True
       Call IO.O
       Graphics.On=False
       If Break Then
          Exit Do
       Endif
       Select Case Lcase$(Strng2)
       Case "[xon]", "[xoff]", "[bell]"
          Eat$=Nul
       Case Else
          Var=Var+1
          If Var>=User.Pagelength-2 Then
             Var=False
             If Continuous=False Then
                Gosub MorePrompt
                Call Modem.ANSI(4,37,15)
                Call ScreenANSI(4,37,15)
                If No Or Quit Then
                   Exit Do
                Endif
             Endif
          Endif
       End Select
    Endif
 Loop
 If Var>1 Then
    If Break=False Then
       Graphics.Off=False
       Gosub MorePrompt
    Endif
 Endif
 Allow.Break=False
 Break=False
 Graphics.Off=True
 Call Modem.ANSI(1,37,15)
 Call ScreenANSI(1,37,15)
 Call Modem.ANSI(4,37,15)
 Call ScreenANSI(4,37,15)
 Strng="[xon]"
 Call Convert.String
 Exit Sub
MorePrompt:
 If VarQ=False Then
    Call Modem.ANSI(1,37,15)
    Call ScreenANSI(1,37,15)
    Call Modem.ANSI(4,37,15)
    Call ScreenANSI(4,37,15)
    If Var1$=".ans" Then
       Buffer=Nul
       Line.Length=1
       No.Echo=True
       Type.Ahead=Nul
       Out2=Nul
       If Environ$("MOREPROMPT")<>"" Then
          Strng=Environ$("MOREPROMPT")
          If Left$(Strng,1)=Chr$(34) Then
             If Right$(Strng,1)=Chr$(34) Then
                Strng=Left$(Strng,Len(Strng)-1)
                Strng=Mid$(Strng,2)
             Endif
          Endif
       Else
          Strng=More$
       Endif
       Graphics.On=True
       Call IO.I
       Call Check.Environ(-1)
       Graphics.On=False
       Return
    Endif
    Call More.Prompt
    Return
 Endif
 Call Modem.ANSI(4,VarQ,VarR)
 Call ScreenANSI(4,VarQ,VarR)
 Buffer=Nul
 Line.Length=1
 No.Echo=True
 Type.Ahead=Nul
 Out2=Nul
 If Environ$("MOREPROMPT")<>"" Then
    Strng=Environ$("MOREPROMPT")
    If Left$(Strng,1)=Chr$(34) Then
       If Right$(Strng,1)=Chr$(34) Then
          Strng=Left$(Strng,Len(Strng)-1)
          Strng=Mid$(Strng,2)
       Endif
    Endif
    Graphics.On=False
    Word.Wrap=-1
    Call IO.I
    Word.Wrap=0
 Else
    Strng=More$
    Graphics.On=False
    Call IO.I
 Endif
 Call Check.Environ(-1)
 Graphics.On=False
 Color.Code=VarQ
 Avatar.Code=VarR
 Return
ErrorResume23x:
 Exit Sub
ErrorTrap23x:
 Resume ErrorResume23x
End Sub

Sub Check.ANSI.Prefix(V%)
 On Local Error Goto Error.Trap27b
 V%=True
 Strng=Out2
 VarX$=Strng
 If Len(VarX$)=0 Then
    Exit Sub
 Endif
 Var2$=ANSIPrefixChar
 VarZ=Len(Var2$)
 If VarZ=False Then
    Return
 Endif
 Do
    If Len(Strng)=False Then
       Exit Do
    Endif
    Var1=Instr(Strng,Var2$)
    If Var1=False Then
       V%=False
       Exit Do
    Endif
    Select Case Lcase$(Mid$(Strng,Var1+VarZ,1))
    Case "f"
       Var4$=Lcase$(Mid$(Strng,Var1+VarZ+1,1))
       Select Case Var4$
       Case "0" To "7"
          Strng=Mid$(VarX$,Var1+VarZ+2)
          VarX$=Strng
       Case "8", "9", "a" To "f"
          Strng=Mid$(VarX$,Var1+VarZ+2)
          VarX$=Strng
       Case Else
          V%=False
          Return
       End Select
    Case "b"
       Var4$=Mid$(Strng,Var1+VarZ+1,1)
       Select Case Var4$
       Case "0" To "7"
          Strng=Mid$(VarX$,Var1+VarZ+2)
          VarX$=Strng
       Case Else
          V%=False
          Return
       End Select
    Case Else
       V%=False
       Return
    End Select
 Loop
Error.Resume27b:
 Exit Sub
Error.Trap27b:
 Resume Error.Resume27b
End Sub

Sub Display.ANSI.Prefixes
 If ANSIPrefixChar=Nul Then
    Strng="ANSI prefix codes not enabled."
    Call IO.O
 Else
    Graphics.Off=True
    Strng="fore-   back-   color     foreground"
    Call IO.O
    Strng="ground  ground  value     hilight"
    Call IO.O
    Graphics.Off=False
    Strng="------  ------  ------    ----------"
    Call IO.O
    Graphics.Off=True
    Strng=" "+ANSIPrefixChar+"F0     "+ANSIPrefixChar+"B0    Black     "+ANSIPrefixChar+"F8  Gray"
    Call IO.O
    Strng=" "+ANSIPrefixChar+"F1     "+ANSIPrefixChar+"B1    Blue      "+ANSIPrefixChar+"F9  Light blue"
    Call IO.O
    Strng=" "+ANSIPrefixChar+"F2     "+ANSIPrefixChar+"B2    Green     "+ANSIPrefixChar+"FA  Light green"
    Call IO.O
    Strng=" "+ANSIPrefixChar+"F3     "+ANSIPrefixChar+"B3    Cyan      "+ANSIPrefixChar+"FB  Light cyan"
    Call IO.O
    Strng=" "+ANSIPrefixChar+"F4     "+ANSIPrefixChar+"B4    Red       "+ANSIPrefixChar+"FC  Light red"
    Call IO.O
    Strng=" "+ANSIPrefixChar+"F5     "+ANSIPrefixChar+"B5    Magenta   "+ANSIPrefixChar+"FD  Light magenta"
    Call IO.O
    Strng=" "+ANSIPrefixChar+"F6     "+ANSIPrefixChar+"B6    Brown     "+ANSIPrefixChar+"FE  Yellow"
    Call IO.O
    Strng=" "+ANSIPrefixChar+"F7     "+ANSIPrefixChar+"B7    White     "+ANSIPrefixChar+"FF  High-intensity white"
    Call IO.O
    Call More.Prompt
 Endif
End Sub

Sub Display.Line(VarX)
 On Local Error Goto ErrTrap11
 Strng=String$(VarX,"-")
 Var=User.LineLength
 If Var>False Then
    If VarX>Var Then
       Var=Var-2
       If Var>False Then
          Strng=String$(Var,"-")
       Else
          Strng=Nul
       Endif
    Endif
 Endif
 If Len(Strng) Then
    Call IO.O
 Endif
ErrResume11:
 Exit Sub
ErrTrap11:
 Resume ErrResume11
End Sub
