 Rem File: IO3.bas - Cmd155.bas
 Rem $Include: 'edit.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

' returns [x]/[xx] selection
Function RT$(V%,S$)
 On Local Error Goto RT.Error
 If V%>MaxTemplate Then
    RT$=S$
    Exit Function
 Endif
 T!=1! ' local record
 If User.Index>SFalse Then
    T!=UserRecord.EditList
    If T!=0! Then
       RT$=S$
       Exit Function
    Endif
 Endif
 Close #TemplateFile
 Open DND.Path+"editdata.dat" For Random Shared As #TemplateFile Len=MaxTemplate
 If T!>Lof(TemplateFile)/MaxTemplate Then
    Close #TemplateFile
    RT$=S$
    Exit Function
 Endif
 Call Read.Record(TemplateFile,T!)
 T$=Mid$(EditCommands,V%,1)
 Close #TemplateFile
 U$=S$
 If T$="0" Then
    Mid$(U$,2,1)="*"
    If Len(U$)=4 Then
       Mid$(U$,3,1)="*"
    Endif
 Endif
 RT$=U$
 Exit Function
RT.Error:
 RT$=S$
End Function

Function YN$(I%)
 If I%=False Then
    YN$="No"
 Else
    YN$="Yes"
 Endif
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 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

Function Config1!(Var)
 On Local Error Goto Error.Trap10z
 Call Read.Message.Record(MessWorkFile9,Var)
 Config1!=UserConfigRecord.UserConfig1
Error.Resume10z:
 Exit Function
Error.Trap10z:
 Resume Error.Resume10z
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

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 IO.O
 On Local Error Goto ErrMain1
 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
    If Break Then
       Exit Do
    Endif
    Count=Count+1
    If Count>Len(Strng) Then
       Exit Do
    Endif
    VarX$=Mid$(Strng,Count,1)
    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
MainExit1:
 Exit Sub
ErrMain1:
 Resume MainExit1
End Sub

Sub Send.ANSI
 On Local Error Goto ErrMain2
 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
MainExit2:
 Exit Sub
ErrMain2:
 Resume MainExit2
End Sub

Sub IO.I
 On Local Error Goto ErrMain3
 If Lost.Carrier Then
    Exit Sub
 Endif
 Call Edit.Status.Line
 Carriage.Input=True
 Strng=Strng+Type.Ahead
 Temp.Prompt=Strng
 Call IO.O
 Out2=Type.Ahead
 Type.Ahead=Nul
 Var!=Timeit!
 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
       If Time.Elapsed(Var!,5!) Then
          Var!=Timeit!
          If Time.Elapsed(Timeout,300!) Then
             Strng=""
             Call IO.O
             Strng="Connect timeout!"
             Call IO.O
             Lost.Carrier=-3
             Exit Sub
          Endif
       Endif
       Call Get.Modem
       Call Check.Break
       Call Keyboard
       If Break Then
          Exit Do
       Endif
       If Len(Buffer) Then
          Char$=Left$(Buffer,1)
          Buffer=Mid$(Buffer,2)
       Endif
       If Local.Mode Then
          Call Release.Time(1)
       Endif
    Loop
    If 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
       Exit Do
    Case 32 To 126
       Type.Error=False
       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
          Lost.Carrier=-1
       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
MainExit3:
 Exit Sub
ErrMain3:
 Resume MainExit3
End Sub

Sub Put.Modem(Var$)
 On Local Error Goto ErrMain4
 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) ' get line status
    If (OutregsX.AX And &H4000)=&H4000 Then ' empty buffer
       Exit Do
    Endif
 Loop
MainExit4:
 Exit Sub
ErrMain4:
 Resume MainExit4
End Sub

Sub Get.Modem
 On Local Error Goto ErrMain5
 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)=False Then
    Exit Sub
 Endif
 Call Driver(2)
End.Input:
 VarX=(OutregsX.AX And &HFF)
 If VarX=3 Or VarX=11 Then
    Call Set.Break
 Else
    Buffer=Buffer+Chr$(VarX)
 Endif
MainExit5:
 Exit Sub
ErrMain5:
 Resume MainExit5
End Sub

Sub Check.Break
 On Local Error Goto Error.Trap21
 If Local.Mode=False Then
    If Lost.Carrier Then
       Exit Sub
    Endif
    If Fossil.Active Then
       InregsX.AX=&H1001
       InregsX.DX=Port
       Call InterruptX(&H14,InregsX,OutregsX)
       If (OutregsX.AX And 1)=1 Then
          Call Set.Break
       Endif
    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 Sleep.Second(Var!)
 On Local Error Goto Error.Trap5
 Timer.Temp!=Timeit!
 Do
    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 Check.Carrier
 On Local Error Goto ErrMain8
 If Local.Mode Then
    Exit Sub
 Endif
 If Lost.Carrier Then
    Exit Sub
 Endif
 Call Driver(3)
 If (OutregsX.AX And &H80)=False Then
    Lost.Carrier=-1
    Strng="Lost carrier!"
    Call Scrn(Strng)
 Endif
MainExit8:
 Exit Sub
ErrMain8:
 Resume MainExit8
End Sub

Sub Keyboard
 On Local Error Goto ErrMain9
 If Lost.Carrier Then
    Exit Sub
 Endif
 VarX$=Inkey$
 Select Case Len(VarX$)
 Case 0
    Exit Sub
 Case 1
    Var=Asc(VarX$)
    Select Case Var
    Case 8, 13, 32 To 126
       Buffer=Buffer+VarX$
    Case 3, 11
       If Allow.Break Then
          Break=True
       Endif
    End Select
 Case 2
    Select Case Asc(Right$(VarX$,1))
    Case 79  ' end
       If Chained=False Then
          Color 7, 0
          Print
       Endif
       Lost.Carrier=-2
    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$
             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
             Lost.Carrier=-2
          Endif
       Endif
    End Select
 End Select
MainExit9:
 Exit Sub
ErrMain9:
 Resume MainExit9
End Sub

Sub Line.Return
 On Local Error Goto ErrMain10
 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
MainExit10:
 Exit Sub
ErrMain10:
 Resume MainExit10
End Sub

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

Sub Back.Space
 On Local Error Goto ErrMain12
 If User.Echo=False Then
    If Local.Mode=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
    Var$=Chr$(27)+"[D"
    Call Put.Screen(Var$)
    Var$=" "
    Call Put.Screen(Var$)
    Var$=Chr$(27)+"[D"
    Call Put.Screen(Var$)
 Else
    Locate Csrlin,Pos(0)-1,0
    Print " ";
    Locate Csrlin,Pos(0)-1,1
 Endif
MainExit12:
 Exit Sub
ErrMain12:
 Resume MainExit12
End Sub

Sub Reset.Cursor
 On Local Error Goto ErrMain13
 Call ScreenANSI(1,37,7)
 Locate Max.Row-1,1,1
 Graphics.Off=False
 Line.Length=False
MainExit13:
 Exit Sub
ErrMain13:
 Resume MainExit13
End Sub

Sub Get.Cursor(Var)
 On Local Error Goto ErrMain14
 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)
MainExit14:
 Exit Sub
ErrMain14:
 Resume MainExit14
End Sub

Sub Scrn(Var$)
 On Local Error Goto ErrMain15
 Dim Scrn.Row As Integer
 Scrn.Row=Max.Row-2
 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>Scrn.Row
    Call Scroll.Screen
 Case Scrn.Row
    If VarC>User.LineLength Then
       Call Put.Screen(Chr$(13))
       If User.Linefeeds=False Then
          Call Put.Screen(Chr$(10))
       Endif
       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$)
MainExit15:
 Exit Sub
ErrMain15:
 Resume MainExit15
End Sub

Sub Scroll.Screen
 On Local Error Goto ErrMain16
 Dim Scroll.Row As Integer
 Scroll.Row=Max.Row-2
 Call VideoInt(6,Scroll.Row*256+&H4F)
 Call VideoInt(2,Scroll.Row*256)
 Locate Max.Row-1,1,1
MainExit16:
 Exit Sub
ErrMain16:
 Resume MainExit16
End Sub

Sub Put.Screen(Var1$)
 On Local Error Goto ErrMain17
 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
MainExit17:
 Exit Sub
ErrMain17:
 Resume MainExit17
End Sub

Sub Local.ANSI(Var1,Var2,Var3)
 On Local Error Goto ErrMain18
 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
MainExit18:
 Exit Sub
ErrMain18:
 Resume MainExit18
End Sub

Sub ScreenANSI(Var1,Var2,Var3)
 On Local Error Goto ErrMain19
 Call Local.ANSI(Var1,Var2,Var3)
 If TempD$<>Nul Then
    Call Scrn(TempD$)
 Endif
MainExit19:
 Exit Sub
ErrMain19:
 Resume MainExit19
End Sub

Sub Modem.ANSI(Var1,Var2,Var3)
 On Local Error Goto ErrMain20
 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
MainExit20:
 Exit Sub
ErrMain20:
 Resume MainExit20
End Sub

Sub ANSI(VarX,VarY,VarZ)
 On Local Error Goto ErrMain21
 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
MainExit21:
 Exit Sub
ErrMain21:
 Resume MainExit21
End Sub

Sub Avatar(VarX,VarY,VarZ)
 On Local Error Goto ErrMain22
 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
MainExit22:
 Exit Sub
ErrMain22:
 Resume MainExit22
End Sub

Sub Convert.Color(VarX,VarY)
 On Local Error Goto ErrMain23
 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, 0
 Else
    If VarB Then
       VarB=VarB-8
       Color ,VarB
    Endif
 Endif
MainExit23:
 Exit Sub
ErrMain23:
 Resume MainExit23
End Sub

Sub Driver(Var)
 On Local Error Goto ErrMain24
 Select Case Var
 Case 1
    InregsX.AX=InregsX.AX Or &H0100
 Case 2
    InregsX.AX=&H0200
 Case 3
    InregsX.AX=&H0300
 End Select
 InregsX.DX=Port
 Call InterruptX(&H14,InregsX,OutregsX)
MainExit24:
 Exit Sub
ErrMain24:
 Resume MainExit24
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
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 Valid(Var$,Var)
 On Local Error Goto ErrMain45
 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
MainExit45:
 Exit Sub
ErrMain45:
 Resume MainExit45
End Sub

Sub More.Prompt
 On Local Error Goto Error.Trap51
 If Break Then
    Exit Sub
 Endif
 VarX=Allow.Break
 Allow.Break=True
 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=Mid$(Strng,2)
          Strng=Left$(Strng,Len(Strng)-1)
       Endif
    Endif
    Word.Wrap=-1
    Call IO.I
    Word.Wrap=0
 Else
    Strng=More$
    Call IO.I
 Endif
 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
 Graphics.Off=Var
 Allow.Break=VarX
Error.Resume51:
 Exit Sub
Error.Trap51:
 Resume Error.Resume51
End Sub

Sub Open.Arrays
 On Local Error Goto Array.Error
 Call Plex.Function(26)
 If (OutregsX.AX And &HFF)=&HFF Then
    Local.ANSI.Color=True
 Else
    Local.ANSI.Color=False
 Endif
 Local.Avatar.Color=False
 Call Plex.Function(27)
 If (OutregsX.AX And &HFF)=&HFF Then
    If (OutregsX.DX And &HFF)=&H16 Then
       Local.Avatar.Color=True
    Endif
 Endif
 Local.Mode=True
 Lost.Carrier=False
 Call Read.Rows(Max.Row)
 Locate Max.Row,1,1
 Call VideoInt(15,0)
 Video.Page=OutregsX.BX
Redim Alignment.Name1(1 To MaxAlignment) As String*7,_
 Alignment.Name2(1 To MaxAlignment) As String*7,_
 Class.Name(1 To MaxClassNames) As String*15,_
 Direction(1 To MaxDirections) As String*9,_
 High.Class.Name(1 To MaxClassNames) As String*15,_
 InventoryNames(1 To MaxItems) As String*8,_
 Numeral(1 To MaxNumerals) As String*5,_
 Race(1 To MaxRaces) As String*8,_
 Room.Array(1 To MaxRoomArrays) As String*40,_
 Stat(1 To MaxStats) As String*12,_
 Training.Stats(1 To MaxClassNames,1 To MaxTrainStats) As Integer,_
 Weapon.Type.Name(1 To MaxWeapons) As String*9
 Exit Sub
Array.Error:
 Color 14,0
 Print
 Print "Error opening arrays. Free more RAM."
 Call Terminate.Program
End Sub

Sub Get.Config
 On Local Error Goto Config.Error
 DND.Path=Environ$("DNDBBS")
 If DND.Path<>Nul Then
    If Right$(DND.Path,1)<>"\" Then
       DND.Path=DND.Path+"\"
    Endif
 Endif
 FileName=DND.Path+"DND.CFG"
 Close #TempFile1
 Open FileName For Input Shared As #TempFile1
 Line Input #TempFile1,Var$
 For Temp1=1 To MaxConfigArray1
    Input #TempFile1,Var!
 Next
 For Temp1=1 To MaxConfigArray2
    Input #TempFile1,Var%
    Select Case Temp1
    Case 48
       Allow.High.Class=Var%
    Case 81
       Allow.Remote.Edit=Var%
    Case 86
       User.Echo=Var%
    Case 87
       User.Linefeeds=Var%
    Case 88
       User.Linelength=Var%
    Case 89
       User.Pagelength=Var%
    Case 90
       User.Wordwrap=Var%
    Case 111
       Disable.DM=Var%
    Case 112
       Disable.Nodes=Var%
    Case 113
       Disable.Sysop=Var%
    End Select
 Next
 For Temp1=1 To MaxConfigArray3
    Line Input #TempFile1,Var$
    Select Case Temp1
    Case 1
       Prelog.FileName=Var$
    Case 3
       Welcome.FileName=Var$
    Case 4
       Notice.FileName=Var$
    Case 11
       Data.Path1=Var$
    Case 12
       MonClass.FileName=Var$
    Case 13
       MonTalk.FileName=Var$
    Case 15
       File.Extension1=Var$
    Case 16
       Room.FileName=Var$
    Case 17
       Object.FileName=Var$
    Case 18
       Monster.FileName=Var$
    Case 19
       Treasure.FileName=Var$
    Case 20
       Spell.FileName=Var$
    Case 21
       User.FileName=Var$
    Case 22
       NonPlayer.FileName=Var$
    Case 28
       Logoff.FileName=Var$
    Case 51
       Usage.FileName=Var$
    Case 52
       Data.Path2=Var$
    Case 53
       Data.Path3=Var$
    Case 54
       Data.Path4=Var$
    Case 55
       Help.FileName1=Var$
    Case 56
       Help.Filename2=Var$
    Case 57
       Team.FileName=Var$
    Case 58
       Public.FileName=Var$
    Case 59
       Message.Base.FileName=Var$
    Case 60
       Private.FileName=Var$
    Case 61
       Help.FileName3=Var$
    Case 62
       File.Extension2=Var$
    Case 65
       Catalog.FileName=Var$
    Case 68
       MessWork.FileName=Var$
    Case 71
       Action.FileName=Var$
    Case 72
       Day.File.FileName=Var$
    Case 76
       Help.FileName4=Var$
    Case 80
       Container.FileName=Var$
    Case 85
       ANSIPrefixChar=Var$
    Case 86
       UserInv.FileName=Var$
    Case 87
       CtnInv.FileName=Var$
    Case 88
       TeamInv.FileName=Var$
    Case 89
       RoomInv.FileName=Var$
    Case 90
       MonInv.FileName=Var$
    Case 91
       Inline.FileName2=Var$
    Case 92
       Inline.FileName1=Var$
    Case 93
       Room.Desc.FileName=Var$
    End Select
 Next
 For Temp1=1 To 10
    For Temp2=1 To 4
       Input #TempFile1,Training.Stats(Temp1,Temp2)
    Next
 Next
 For Temp1=1 To 20
    Line Input #TempFile1,Room.Array(Temp1)
 Next
 MessWork.FileName=Data.Path3+MessWork.FileName
 For Temp1=1 To 10
    Line Input #TempFile1,High.Class.Name(Temp1)
 Next
 For Temp1=1 To 8
    Line Input #TempFile1,Race(Temp1)
 Next
 For Temp1=1 To 10
    Line Input #TempFile1,Class.Name(Temp1)
 Next
 For Temp1=1 To 7
    Line Input #TempFile1,Stat(Temp1)
 Next
 For Temp1=1 To 12
    Line Input #TempFile1,Direction(Temp1)
 Next
 For Temp1=1 To 10
    Line Input #TempFile1,Numeral(Temp1)
 Next
 For Temp1=1 To 4
    Line Input #TempFile1,Weapon.Type.Name(Temp1)
 Next
 For Temp1=1 To 3
    Line Input #TempFile1,Alignment.Name1(Temp1)
 Next
 For Temp1=1 To 3
    Line Input #TempFile1,Alignment.Name2(Temp1)
 Next
 For Temp1=1 To MaxUserCommands
    Line Input #TempFile1,Var$
    For Temp2=1 To 3
       Line Input #TempFile1,Var$
    Next
    Input #TempFile1,Var%
    For Temp2=1 To 8
       Input #TempFile1,Var%
    Next
    For Temp2=1 To 4
       Input #TempFile1,Var%
    Next
    Input #TempFile1,Var%
    Input #TempFile1,Var%
 Next
 For Temp1=1 To MaxDMcommands
    Line Input #TempFile1,Var$
    Input #TempFile1,Var%
    For Temp2=1 To 3
       Input #TempFile1,Var%
    Next
 Next
 For Temp1=1 To MaxSysopCommands
    Line Input #TempFile1,Var$
    Input #TempFile1,Var%
 Next
 For Temp1=1 To MaxNodeCommands
    Line Input #TempFile1,Var$
    For Temp2=1 To 8
       Input #TempFile1,Var%
    Next
 Next
 For Temp1=1 To MaxLetters
    Input #TempFile1,Var%
 Next
 For Temp1=1 To MaxStrips
    Line Input #TempFile1,Var$
 Next
 For Temp1=1 To 10
    Line Input #TempFile1,Var$
    Input #TempFile1,Var%
    Input #TempFile1,Var%
 Next
 For Temp1=1 To 10
    Line Input #TempFile1,InventoryNames(Temp1)
 Next
 Exit Sub
Config.Error:
 Call Error.List(Err)
 Print
 Color 15,0
 Print "Editor menu error:"
 Color 14,0
 Print
 Print "Error '"+Strng+"' reading "+Lcase$(FileName)+"."
 Print "Increase files= in config.sys or config.nt, or run Dndcnfg."
 Call Terminate.Program
End Sub

Sub Increase.Files
 On Local Error Goto Increase.Error
 Close
 Call StdinInt(62,0)
 PSP.Segment=OutregsX.BX
 Def Seg=PSP.Segment
 Command.Line=&H80
 Command.Tail=Command.Line+60
 For Var=1 To 54
    Poke Command.Tail+Var-1,&HFF
 Next
 For Var=1 To 4
    File.Handle=Peek(&H18+Var-1)
    Poke Command.Tail+Var-1,File.Handle
 Next
 Poke &H32,54
 Poke &H34,Command.Tail
 Def Seg
 Close
 Exit Sub
Increase.Error:
 Color 14,0
 Print
 Print "Error increasing file handles."
 Print "Increase files= in config.sys or config.nt, or run Dndcnfg."
 Call Terminate.Program
End Sub

Sub Make.FileNames
 On Local Error Goto Make.Error
 Out2=Environ$("DNDDAT")
 If Out2<>Nul Then
    If Right$(Out2,1)<>"\" Then
       Out2=Out2+"\"
    Endif
    Data.Path1=Out2
 Endif
 Out2=Environ$("DNDDOC")
 If Out2<>Nul Then
    If Right$(Out2,1)<>"\" Then
       Out2=Out2+"\"
    Endif
    Data.Path2=Out2
 Endif
 Out2=Environ$("DNDTEMP")
 If Out2<>Nul Then
    If Right$(Out2,1)<>"\" Then
       Out2=Out2+"\"
    Endif
    Data.Path3=Out2
 Endif
 Out2=Environ$("DNDMESS")
 If Out2<>Nul Then
    If Right$(Out2,1)<>"\" Then
       Out2=Out2+"\"
    Endif
    Data.Path4=Out2
 Endif
 DOS.Exit="EDTDOS"+Rtrim$(NodeX)+".BAT"
 Day.File.FileName=Data.Path1+Day.File.FileName
 Catalog.FileName=Data.Path2+Catalog.FileName+File.Extension2
 Logoff.FileName=Data.Path1+Logoff.FileName+File.Extension1
 Notice.FileName=Data.Path1+Notice.FileName+File.Extension1
 Prelog.FileName=Data.Path1+Prelog.FileName+File.Extension1
 Welcome.FileName=Data.Path1+Welcome.FileName+File.Extension1
 User.FileName=Data.Path1+User.FileName+File.Extension1
 NonPlayer.FileName=Data.Path1+NonPlayer.FileName+File.Extension1
 Room.FileName=Data.Path1+Room.FileName+File.Extension1
 Object.FileName=Data.Path1+Object.FileName+File.Extension1
 Monster.FileName=Data.Path1+Monster.FileName+File.Extension1
 Treasure.FileName=Data.Path1+Treasure.FileName+File.Extension1
 MonTalk.FileName=Data.Path1+MonTalk.FileName+File.Extension1
 MonClass.FileName=Data.Path1+MonClass.FileName+File.Extension1
 Spell.FileName=Data.Path1+Spell.FileName+File.Extension1
 Action.FileName=Data.Path1+Action.FileName+File.Extension1
 Help.FileName1=Data.Path1+Help.FileName1+File.Extension1
 Help.FileName2=Data.Path1+Help.FileName2+File.Extension1
 Team.FileName=Data.Path1+Team.FileName+File.Extension1
 Container.FileName=Data.Path1+Container.FileName+File.Extension1
 Message.Base.FileName=Data.Path4+Message.Base.FileName+File.Extension1
 Logon.Help.FileName=Data.Path1+Help.FileName3+File.Extension1
 UserInv.FileName=Data.Path1+UserInv.FileName+File.Extension1
 CtnInv.FileName=Data.Path1+CtnInv.FileName+File.Extension1
 TeamInv.FileName=Data.Path1+TeamInv.FileName+File.Extension1
 RoomInv.FileName=Data.Path1+RoomInv.FileName+File.Extension1
 MonInv.FileName=Data.Path1+MonInv.FileName+File.Extension1
 Room.Desc.FileName=Data.Path1+Room.Desc.FileName+File.Extension1
 Usage.FileName=Data.Path1+Usage.FileName+File.Extension1
 Exit Sub
Make.Error:
 Call Error.List(Err)
 Print
 Color 15,0
 Print "Editor menu error:"
 Color 14,0
 Print
 Print "Error '"+Strng+"' making "+Lcase$(FileName)+"."
 Print "Increase files= in config.sys or config.nt, or run Dndcnfg."
 Call Terminate.Program
End Sub

Sub Open.Files
 On Local Error Goto Open.Error
 Close
 ActionRecLen=Len(ActionRecord)
 BufferRecLen=Len(BufferRecord)
 ContainerRecLen=Len(ContainerRecord)
 HelpRecLen1=Len(HelpRecord1)
 HelpRecLen2=Len(HelpRecord2)
 HelpRecLen3=Len(HelpRecord3)
 MessBaseRecLen=Len(MessageBaseRecord)
 MessageRecLen=Len(BufferRecord)
 MonsterRecLen=Len(MonsterRecord)
 NewMessRecLen=Len(NewMessages)
 TableRecLen=Len(TableRecord)
 UserRecLen=Len(UserRecord)
 UserProfileRecLen=Len(UserProfile)
 MonClassRecLen=Len(MonClassRecord)
 MonTalkRecLen=Len(BufferRecord)
 NonPlayerRecLen=Len(MonsterRecord)
 ObjectRecLen=Len(ObjectRecord)
 RoomDescLen=Len(BufferRecord)
 RoomRecLen=Len(RoomRecord)
 SpellRecLen=Len(SpellRecord)
 TeamRecLen=Len(TeamRecord)
 TreasureRecLen=Len(TreasureRecord)
 MessWorkRecLen1=Len(MessWorkRecord1)
 MessWorkRecLen2=Len(MessWorkRecord2)
 MessWorkRecLen3=Len(MessWorkRecord3)
 MessWorkRecLen5=Len(MessWorkRecord5)
 MessWorkRecLen4=Len(MessWorkRecord4)
 MessWorkRecLen6=Len(MessWorkRecord6)
 MessWorkRecLen7=Len(MessWorkRecord7)
 FileName=DND.Path+"ACCOUNTS.SIC"
 Open FileName For Random Shared As #SicFile Len=UserProfileRecLen

 FileName=User.FileName
 Open FileName For Random Shared As #UserFile Len=UserRecLen
 Open FileName For Random Shared As #UserFile2 Len=UserRecLen

 FileName=NonPlayer.FileName
 Open FileName For Random Shared As #NonPlayerFile Len=NonPlayerRecLen
 FileName=Room.FileName
 Open FileName For Random Shared As #RoomFile Len=RoomRecLen
 FileName=Object.FileName
 Open FileName For Random Shared As #ObjectFile Len=ObjectRecLen
 FileName=Monster.FileName
 Open FileName For Random Shared As #MonsterFile Len=MonsterRecLen
 FileName=Treasure.FileName
 Open FileName For Random Shared As #TreasureFile Len=TreasureRecLen
 FileName=MonTalk.FileName
 Open FileName For Random Shared As #MonTalkFile Len=MonTalkRecLen
 FileName=MonClass.FileName
 Open FileName For Random Shared As #MonClassFile Len=MonClassRecLen
 FileName=Spell.FileName
 Open FileName For Random Shared As #SpellFile Len=SpellRecLen
 FileName=Action.FileName
 Open FileName For Random Shared As #ActionFile Len=ActionRecLen
 FileName=Help.FileName1
 Open FileName For Random Shared As #HelpFile1 Len=HelpRecLen1
 FileName=Team.FileName
 Open FileName For Random Shared As #TeamFile Len=TeamRecLen
 FileName=Container.FileName
 Open FileName For Random Shared As #ContainerFile Len=ContainerRecLen
 FileName=Message.Base.FileName
 Open FileName For Random Shared As #MessBaseFile Len=MessBaseRecLen
 FileName=UserInv.FileName
 Open FileName For Random Shared As #UserInvFile Len=MessWorkRecLen6
 FileName=CtnInv.FileName
 Open FileName For Random Shared As #CtnInvFile Len=MessWorkRecLen6
 FileName=TeamInv.FileName
 Open FileName For Random Shared As #TeamInvFile Len=MessWorkRecLen6
 FileName=RoomInv.FileName
 Open FileName For Random Shared As #RoomInvFile Len=MessWorkRecLen6
 FileName=MonInv.FileName
 Open FileName For Random Shared As #MonInvFile Len=MessWorkRecLen6
 FileName=Room.Desc.FileName
 Open FileName For Random Shared As #RoomDescFile Len=RoomDescLen
 FileName=MessWork.FileName+"1"+File.Extension1
 Open FileName For Random Shared As #MessWorkFile1 Len=MessWorkRecLen1
 FileName=MessWork.FileName+"6"+File.Extension1
 Open FileName For Random Shared As #MessWorkFile6 Len=MessWorkRecLen6
 FileName=MessWork.FileName+"7"+File.Extension1
 Open FileName For Random Shared As #MessWorkFile7 Len=MessWorkRecLen7
 Exit Sub
Open.Error:
 Call Error.List(Err)
 Print
 Color 15,0
 Print "Editor menu error:"
 Color 14,0
 Print
 Print "Error '"+Strng+"' making "+Lcase$(FileName)+"."
 Print "Increase files= in config.sys or config.nt, or run Dndcnfg."
 Call Terminate.Program
End Sub

Sub Error.List(Var2)
 On Local Error Goto Error.Trap10a
 Select Case Var2
 Case 52
    Strng="bad file name or number"
 Case 53
    Strng="file not found"
 Case 55
    Strng="file already open"
 Case 57
    Strng="device i/o error"
 Case 61
    Strng="disk full"
 Case 62
    Strng="input past eof"
 Case 64
    Strng="bad file name"
 Case 67
    Strng="not enough file handles"
 Case 68
    Strng="device unavailable"
 Case 70
    Strng="permission denied"
 Case 71
    Strng="disk not ready"
 Case 75
    Strng="path/file access error"
 CASE 76
    Strng="pathname not found"
 Case Else
    Strng=Ltrim$(Str$(Var2))
 End Select
Error.Resume10a:
 Exit Sub
Error.Trap10a:
 Resume Error.Resume10a
End Sub

Sub Decrease.Files
 On Local Error Goto Decrease.Error
 Close
 Call StdinInt(62,0)
 PSP.Segment=OutregsX.BX
 Def Seg=PSP.Segment
 Poke &H32,20
 Poke &H34,&H18
 Def Seg
 Close
Decrease.Resume:
 Exit Sub
Decrease.Error:
 Print "Error"+Str$(Err)+" closing file handles. Free more RAM."
 Resume Decrease.Resume
End Sub

Sub Terminate.Program
 On Local Error Goto ErrMain42
 Call Clear.Status.Line
 Color 15,0
 Call ScreenANSI(1,37,7)
 Cls
 Call ScreenANSI(3,0,0)
 Call Save.Screen2(-1)
' Locate Max.Row,1,1
 If TempX=0 Then TempX=1
 Locate TempX,1,1
 Color 15,0
 Print
 Print "Now exiting the Dndbbs Menu Editor.."
 Color 7,0
 Call Decrease.Files
MainExit42:
 End 0
ErrMain42:
 Resume MainExit42
End Sub

Sub Save.Screen2(Var)
 On Local Error Goto Error.Trap62
 If Var=False Then
    VarX3=(Max.Row-1)*80+80
    Redim Temp.ArrayY(VarX3) As Long
    Redim Temp.ArrayZ(VarX3) As Double
    For Var1=1 To Max.Row
       For Var2=1 To 80
          TempZ1=Screen(Var1,Var2)
          TempZ2=Screen(Var1,Var2,1)
          VarX2=(Var1-1)*80+Var2
          Temp.ArrayY(VarX2)=TempZ1
          Temp.ArrayZ(VarX2)=TempZ2
       Next
    Next
 Else
    Cls
    For VarX=Max.Row To 1 Step -1
       For VarY=1 To 80
          VarX2=(VarX-1)*80+VarY
          If Temp.ArrayY(VarX2)<>32 Then
             Goto Next.Line
          Endif
       Next
    Next
Next.Line:
    TempX=VarX
    For Var1=1 To VarX ' Max.Row
       For Var2=1 To 80
          VarX2=(Var1-1)*80+Var2
          VarB=Int(Temp.ArrayZ(VarX2)/16)
          VarF=Temp.ArrayZ(VarX2) Mod 16
          TempZ1=Temp.ArrayY(VarX2)
          Locate Var1,Var2,0
          Color VarF,VarB
          Print Chr$(TempZ1);
       Next
    Next
 Endif
Error.Resume62:
 Exit Sub
Error.Trap62:
 Resume Error.Resume62
End Sub

Function GetFilename$(Var1$,Var2$)
 On Local Error Goto Error.Trap100
 Var=16
 Do
    Var=Var+1
    VarF$=Var1$+Mid$(Str$(Var),2)+"."+Var2$
    If Dir$(VarF$)=Nul Then
       GetFilename$=VarF$
       Exit Function
    Endif
 Loop
Error.Resume100:
 Exit Function
Error.Trap100:
 Resume Error.Resume100
End Function

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$=Rtrim$(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 Dot.Display(VarA,VarB,VarC!)
 On Local Error Goto ErrResume66
 VarG!=Timeit!-VarC!
 If VarG!<SFalse Then
    VarG!=Elapsed.Time!+86400!
 Endif
 If VarG!>=1! Then
    VarC!=Timeit!
    If VarA=False Then
       VarB=VarB+1
       Carriage.Return=True
       Graphics.Off=True
       Strng="."
       Call IO.O
       If VarB=5 Then
          VarA=True
          VarB=False
       Endif
    Else
       VarB=VarB+1
       Call Back.Space
       Carriage.Return=True
       Strng=" "
       Call IO.O
       Call Back.Space
       If VarB=5 Then
          VarA=False
          VarB=False
       Endif
    Endif
 Endif
ErrExit66:
 Exit Sub
ErrResume66:
 Resume ErrExit66
End Sub

Sub Search.Mess2(Var)
 On Local Error Goto ErrMain40
 Var=False
 For VarX=1 To MaxNodes+1
    If VarX<=Lof(MessWorkFile1)/MessWorkRecLen1 Then
       Call Read.Message.Record(MessWorkFile1,VarX)
       If MessWorkRecord1.ActiveNode Then
          Var=-1
          Exit Sub
       Endif
       If MessWorkRecord1.UserIndex>SFalse Then
          Var=-1
          Exit Sub
       Endif
    Endif
 Next
MainExit40:
 Exit Sub
ErrMain40:
 Resume MainExit40
End Sub

Sub Out.File(Var$)
 On Local Error Goto ErrorTrap23
 If Dir$(Var$)=Nul Then
    Exit Sub
 Endif
 Graphics.Off=False
 Strng="File list. "
 Var2$="Press <ctrl-break>/<ctrl-c> to interrupt."
 If Local.Mode=False Then
    Var2$="Press <control-c>/<control-k> to interrupt."
 Endif
 Strng=Strng+Var2$
 Call IO.O
 Allow.Break=True
 Break=False
 Continuous=False
 Graphics.Off=True
 Var=1
 Close #TempFile1
 Open Var$ For Input Shared As #TempFile1
 Do While Lost.Carrier=False
    Allow.Break=True
    If Eof(TempFile1) Then
       Exit Do
    Endif
    Line Input #TempFile1,Strng
    If Lcase$(Strng)="[eof]" Then
       Exit Do
    Endif
    Call IO.O
    If Break Then
       Exit Do
    Endif
    Var=Var+1
    If Var>=User.Pagelength-2 Then
       Var=False
       If Continuous=False Then
          Call More.Prompt
          If No Or Quit Then
             Exit Do
          Endif
       Endif
    Endif
 Loop
 Allow.Break=False
 Break=False
 If Var Then
    Call More.Prompt
 Endif
ErrorResume23:
 Exit Sub
ErrorTrap23:
 Resume ErrorResume23
End Sub

Sub Read.ANSI.Input
 On Local Error Goto Error.Trap73
 TempX$=Inkey$
 If Len(TempX$) Then
    Exit Sub
 Endif
 ' control-break
 DEF SEG = &H40
 X = PEEK(&H71)
 POKE &H71, &H0
 DEF SEG
 IF X = 128 THEN
    TempX$=Chr$(0)+Chr$(0)
    Exit Sub
 END IF
 If Local.Mode Then
    Call Release.Time(1)
    Exit Sub
 Endif
 Call Check.Carrier
 Call Get.Modem
 Select Case Len(Buffer)
 Case 0
    Eat$ = Nul
 Case 1
    Select Case Buffer
    Case Chr$(127) ' delete
       TempX$=Chr$(0)+Chr$(83)
       Buffer=Nul
    Case Chr$(27) ' escape
       Eat$ = Nul
    Case Chr$(21) ' ^U = pageup
       TempX$=Chr$(0)+Chr$(73)
       Buffer=Nul
    Case Chr$(14) ' ^N = pagedown
       TempX$=Chr$(0)+Chr$(81)
       Buffer=Nul
    Case Chr$(22) ' ^V = insert
       TempX$=Chr$(0)+Chr$(82)
       Buffer=Nul
    Case Else
       TempX$=Buffer
       Buffer=Nul
    End Select
 Case 2
    Select Case Ucase$(Buffer)
    Case Chr$(27)+"I" ' up
       TempX$=Chr$(0)+Chr$(72)
       Buffer=Nul
    Case Chr$(27)+"M" ' down
       TempX$=Chr$(0)+Chr$(80)
       Buffer=Nul
    Case Chr$(27)+"K" ' right
       TempX$=Chr$(0)+Chr$(77)
       Buffer=Nul
    Case Chr$(27)+"J" ' left
       TempX$=Chr$(0)+Chr$(75)
       Buffer=Nul
    Case Chr$(27)+"O" ' home
       TempX$=Chr$(0)+Chr$(71)
       Buffer=Nul
    Case Chr$(27)+"L" ' end
       TempX$=Chr$(0)+Chr$(79)
       Buffer=Nul
    Case Chr$(27)+"U" ' pageup
       TempX$=Chr$(0)+Chr$(73)
       Buffer=Nul
    Case Chr$(27)+"N" ' pagedown
       TempX$=Chr$(0)+Chr$(81)
       Buffer=Nul
    Case Chr$(27)+Chr$(27) ' exit
       TempX$=Chr$(27)
       Buffer=Nul
    Case Chr$(27)+"["
       Eat$ = Nul
    Case Else
       Buffer=Nul
    End Select
 Case 3
    Select Case Buffer
    Case Chr$(27)+"[A" ' Up ^[[A
       TempX$=Chr$(0)+Chr$(72)
       Buffer=Nul
    Case Chr$(27)+"[B" ' Down ^[[B
       TempX$=Chr$(0)+Chr$(80)
       Buffer=Nul
    Case Chr$(27)+"[C" ' Right ^[[C
       TempX$=Chr$(0)+Chr$(77)
       Buffer=Nul
    Case Chr$(27)+"[D" ' Left ^[[D
       TempX$=Chr$(0)+Chr$(75)
       Buffer=Nul
    Case Chr$(27)+"[H" ' Home ^[[H
       TempX$=Chr$(0)+Chr$(71)
       Buffer=Nul
    Case Chr$(27)+"[K" ' End ^[[K
       TempX$=Chr$(0)+Chr$(79)
       Buffer=Nul
    Case Else
       Buffer=Nul
    End Select
 Case Else
    Var$=Nul
    Buffer=Nul
 End Select
Error.Resume73:
 Exit Sub
Error.Trap73:
 Resume Error.Resume73
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
    If Logged.In Then
       Var$="Enter (B)reak, (C)ancel, (L)ogoff user, (A)bort node: "
    Else
       Var$="Enter (B)reak, (C)ancel, (A)bort node: "
    Endif
 Else
    If Logged.In Then
       Var$="Enter (C)ancel, (L)ogoff user, (A)bort node: "
    Else
       Var$="Enter (C)ancel, (A)bort node: "
    Endif
 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
          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"
          If Allow.Break Then
             Call Scrn("B")
             Call Scrn(Chr$(13)+Chr$(10))
             V$=Inkey$
             Call Set.Break
             Exit Do
          Endif
       Case "C"
          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"
          If Logged.In Then
             Call Scrn("L")
             V$=Inkey$
             Lost.Carrier=-2
             Exit Do
          Endif
       Case "A"
          Call Scrn("A")
          V$=Inkey$
          Color 7,0
          Print
          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
    Break=True
    No=True
    Quit=True
 Endif
Error.Resume22:
 Exit Sub
Error.Trap22:
 Resume Error.Resume22
End Sub

Sub Scrn.Output(Var$)
 On Local Error Goto Error.Trap74
 VarX$=Var$
 For VarX=1 To Len(VarX$)
    V=Asc(Mid$(VarX$,VarX,1))
    Select Case V ' unprintable characters
    Case 0, 7 To 13, 26 To 31
       CALL Modem.ANSI(4, 33, 0)
       Call Put.Modem("?")
       CALL Modem.ANSI(4, 37, 0)
       If Local.ANSI.Color Then
          CALL ScreenANSI(4, 33, 0)
          Call StdinInt(6,63) ' ?
          CALL ScreenANSI(4, 37, 0)
       Else
          Color 14,0
          Print "?";
          Color 15,0
       Endif
    Case 255
       Call Put.Modem(Chr$(V))
       If Local.ANSI.Color Then
          Call StdinInt(6,32)
       Else
          Print Chr$(32);
       Endif
    Case Else
       Call Put.Modem(Chr$(V))
       If Local.ANSI.Color Then
          Call StdinInt(6,V)
       Else
          Print Chr$(V);
       Endif
    End Select
 Next
Error.Resume74:
 Exit Sub
Error.Trap74:
 Resume Error.Resume74
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
    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 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

' 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

' 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
 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
 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
    MessWorkRecord2.Message2=Str$(TempX)+TempA$
 Else
    MessWorkRecord2.Message2=Out4
 Endif
 Call Write.Record(MessWorkFile2,Var!)
ErrorResume15:
 Exit Sub
ErrorTrap15:
 Resume ErrorResume15
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
    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=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

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
    Exit Sub
 Case 71 ' home
    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 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 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

' function to match case-sensitive substring with ?, * characters in substring
SUB InstrSUB1(Var,Var$,VarQ)

' see if Var$ matches in Strng
On Local Error Goto ErrorTrap24x5

' store case-sensitive string match variables
If VarQ Then
   S2$ = Var$
   S3$ = Strng
Else
   S2$ = Lcase$(Var$)
   S3$ = Lcase$(Strng)
Endif

' check default instr
IF INSTR(S2$, "*") = 0 THEN
   IF INSTR(S2$, "?") = 0 THEN
      Var = INSTR(S3$, S2$)
      EXIT SUB
   END IF
END IF

Var = -1 ' assume match

' see if S2$ matches in S3$ with substrings
FOR S3 = 1 TO LEN(S3$)
   S1$ = MID$(S3$, S3)
   P1 = 1 ' pointer to S1$
   P2 = 1 ' pointer to S2$
   DO
      ' check match
      IF P2 > LEN(S2$) THEN
         EXIT SUB
      END IF

      ' check character in S2$ at P2
      V$ = MID$(S2$, P2, 1)
      SELECT CASE V$
      CASE "*" ' global character
         ' scan to next char
         IF P2 > LEN(S2$) THEN
            EXIT DO
         END IF
         S4$ = MID$(S2$, P2 + 1, 1)
         SELECT CASE S4$
         CASE "*", "?"
            P2 = P2 + 1
         CASE ELSE
            DO
               IF MID$(S1$, P1, 1) = S4$ THEN
                  EXIT DO
               END IF
               IF P1 >= LEN(S1$) THEN
                  EXIT DO
               END IF
               P1 = P1 + 1
            LOOP
            P2 = P2 + 1
         END SELECT
      CASE "?" ' wildcard character
         P1 = P1 + 1
         P2 = P2 + 1
      CASE ELSE ' ascii character
         IF MID$(S1$, P1, 1) <> V$ THEN ' no match
            EXIT DO
         END IF
         P1 = P1 + 1
         P2 = P2 + 1
      END SELECT
   LOOP
NEXT
Var = 0 ' no match
EXIT SUB
ErrorResume24x5:
 Exit Sub
ErrorTrap24x5:
 Resume ErrorResume24x5
End Sub
