 Rem File: Cmd086.bas
 Rem Sub: Mail
 Rem $Include: 'dndbbs.inc'
 On Error Goto Main.Error
 If Chained=0 Then ' local mode
    Call Get.Node
    Call Open.Arrays
    Call Get.Config
    Call Increase.Files
    Call Make.FileNames
    Call Reset.Cursor
    Call Detect.Share
    Call Open.Files
    Call Read.Options
    Call Valid.Node
    Call Save.Screen2(0)
    Color 14,0
    Print "DNDBBS CMD086 - Mail"
    Var$=Nul
    If Command$<>Nul Then
       Var$=Command$
    Endif
    Call Alt.Login(Var,Var$)
    If Var=False Then
       If Lost.Carrier=False Then
          Color 14,0
          Print "Codename not found."
       Endif
       Call More.Prompt
       Goto Main.Resume
    Endif
    Call Search.Mess.File(User.Index,Var1)
    If Var1 Then
       Color 14,0
       Print "Codename is in use."
       Call More.Prompt
       Goto Main.Resume
    Endif
    Call Get.User.Stats(Var)
    Timeon=Timeit!
    Time.Left=3600!
 Endif
 Call Mail
Main.Resume:
 If Chained=-2 Then
    Chain DND.Path+"DNDBBS.EXE"
 Endif
 Call Clear.Status.Line
 Call ScreenANSI(1,37,7)
 Color 7, 0
 Cls
 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 Mail.."
 Color 7,0
 Call Decrease.Files
 End
Main.Error:
 Resume Main.Resume

Sub Mail
 On Local Error Goto Error.Trap34
 Redim Temp.ArrayS(1 To 19) As String
 Gosub Get.Config
 If VarZ Then
    Option20=-1:Option21=-1:Option22=-1:Option23=-1:Option24=-1:Option25=-1
 Endif
 If GuestLogin Then
    If GuestRecord.GuestAllowMail=False Then
       Strng="Guests cannot use mail.."
       Call IO.O
       Exit Sub
    Endif
 Endif
 If optionx1=False Then
    option1=0:option2=0:option3=0:option4=0:option5=0
    option6=0:option7=0:option8=0:option9=0:option10=0
 Endif
 Do While Lost.Carrier=False
    Call Mail.Status.Line
    No.Input.Out="Q"
    Graphics.Off=False
    Strng="Mail command(?=Help): "
    Call IO.I
    VarX=True
    Out3=Ucase$(Out2)
    Select Case Out3
    Case "E" ' enter
       Select Case Option20
       Case 0
          ' nul
       Case -1
          Call Select.Base(VarX,0)
          If VarX Then
             Call Open.Mail
          Endif
       Case Else
          If Option20>0 Then
             If UserRecord.Level>=Option20 Then
                Call Select.Base(VarX,0)
                If VarX Then
                   Call Open.Mail
                Endif
             Endif
          Endif
       End Select
    Case "K" ' kill
       Select Case Option21
       Case 0
          ' nul
       Case -1
          Call Select.Base(VarX,0)
          If VarX Then
             Call Open.Mail
          Endif
       Case Else
          If Option21>0 Then
             If UserRecord.Level>=Option21 Then
                Call Select.Base(VarX,0)
                If VarX Then
                   Call Open.Mail
                Endif
             Endif
          Endif
       End Select
    Case "L" ' lock
       Select Case Option22
       Case 0
          VarX=False
       Case -1
          ' nul
       Case Else
          If UserRecord.Level>=Option22 Then
             ' nul
          Else
             VarX=False
          Endif
       End Select
    Case "N" ' new
       Select Case Option23
       Case 0
          ' nul
       Case -1
          Call Select.Base(VarX,0)
          If VarX Then
             Call Open.Mail
          Endif
       Case Else
          If Option23>0 Then
             If UserRecord.Level>=Option23 Then
                Call Select.Base(VarX,0)
                If VarX Then
                   Call Open.Mail
                Endif
             Endif
          Endif
       End Select
    Case "R" ' read
       Select Case Option24
       Case 0
          ' nul
       Case -1
          Call Select.Base(VarX,0)
          If VarX Then
             Call Open.Mail
          Endif
       Case Else
          If Option24>0 Then
             If UserRecord.Level>=Option24 Then
                Call Select.Base(VarX,0)
                If VarX Then
                   Call Open.Mail
                Endif
             Endif
          Endif
       End Select
    Case "U" ' unlock
       Select Case Option25
       Case 0
          VarX=False
       Case -1
          ' nul
       Case Else
          If UserRecord.Level>=Option25 Then
             ' nul
          Else
             VarX=False
          Endif
       End Select

    Case "D" ' display messbases
       If optionx1=0 Then
          VarX=False
       Endif
    Case "M" ' search messbases
       If optionx1=0 Then
          VarX=False
       Endif
    Case "S" ' search messages
       VarX=False
       If optionx1 Then
          Call Select.Base(VarX,0)
          If VarX Then
             Call Open.Mail
          Endif
       Endif
    Case "C" ' create
       VarX=0
       If Option1 Then
          VarX=-1
          If Option2 Then
             If Sysop=False Then
                VarX=0
             Endif
          Endif
       Endif

    ' extended mail functions
    Case "W" ' delete message base
       VarX=False
       VarZ=False
       If Sysop Then
          If Option4 Then
             VarZ=True
          Endif
       Else
          If Option8 Then
             VarZ=True
          Endif
       Endif
       If VarZ Then
          Call Select.Base(VarX,-1)
          If VarX Then
             Call Open.Mail
          Endif
       Endif
    Case "X" ' edit message base
       VarX=False
       VarZ=False
       If Sysop Then
          If Option6 Then
             VarZ=True
          Endif
       Else
          If Option10 Then
             VarZ=True
          Endif
       Endif
       If VarZ Then
          Call Select.Base(VarX,-1)
       Endif
    Case "Y" ' undelete message base
       VarX=False
       If Sysop Then
          If Option5 Then
             VarX=True
          Endif
       Else
          If Option9 Then
             VarX=True
          Endif
       Endif
    Case "Z" ' undelete message
       VarX=False
       VarZ=False
       If Sysop Then
          If Option3 Then
             VarZ=True
          Endif
       Else
          If Option7 Then
             VarZ=True
          Endif
       Endif
       If VarZ Then
          Call Select.Base(VarX,0)
          If VarX Then
             Call Open.Mail
          Endif
       Endif
    End Select

    ' check valid messbase flag
    If VarX Then
       Select Case Out3
       Case "?"
          Gosub Mail.Help
       Case "A"
          Graphics.Off=True
          Call Display.ANSI.Prefixes
       Case "H"
          Stored.Parsed.Command1="MAIL"
          Call Read.Help
       Case "C"
          Call Create.Base
       Case "D"
          Call Display.Messbases
       Case "E"
          Call Enter.Message
       Case "K"
          Call Kill.Message
       Case "L"
          Call Lock.Mailbox(True)
       Case "M"
          Call Search.Messbases
       Case "N"
          Call New.Messages
       Case "R"
          Call Read.Messages
       Case "S"
          Call Search.Messages
       Case "U"
          Call Lock.Mailbox(False)
       Case "W"
          Call Delete.Messbase
       Case "X"
          Call Edit.Messbase
       Case "Y"
          Call Undelete.Messbase
       Case "Z"
          Call Undelete.Message
       Case "Q"
          Exit Do
       End Select
    Else
       Graphics.Off=False
       Strng="Type ? for Help."
       Call IO.O
    Endif
 Loop
 Erase Temp.ArrayS
 Exit Sub
Mail.Help:
 Graphics.Off=False
 Strng="Mail functions:"
 Call IO.O
 Graphics.Off=True
 ' standard functions
 If ANSIPrefixChar<>Nul Then
    Strng="[A]nsi code list"
    Call IO.O
 Endif
 Strng="[H]elp file list"
 Call IO.O

 Select Case Option20
 Case 0
    Strng="[*]nter message"
    Call IO.O
 Case -1
    Strng="[E]nter message"
    Call IO.O
 Case Else
    If UserRecord.Level >= Option20 Then
       Strng="[E]nter message"
       Call IO.O
    Else
       Strng="[*]nter message"
       Call IO.O
    Endif
 End Select

 Select Case Option21
 Case 0
    Strng="[*]ill message"
    Call IO.O
 Case -1
    Strng="[K]ill message"
    Call IO.O
 Case Else
    If UserRecord.Level >= Option21 Then
       Strng="[K]ill message"
       Call IO.O
    Else
       Strng="[*]ill message"
       Call IO.O
    Endif
 End Select

 Select Case Option22
 Case 0
    Strng="[*]ock mailbox"
    Call IO.O
 Case -1
    Strng="[L]ock mailbox"
    Call IO.O
 Case Else
    If UserRecord.Level >= Option22 Then
       Strng="[L]ock mailbox"
       Call IO.O
    Else
       Strng="[*]ock mailbox"
       Call IO.O
    Endif
 End Select

 Select Case Option23
 Case 0
    Strng="[*]ew messages"
    Call IO.O
 Case -1
    Strng="[N]ew messages"
    Call IO.O
 Case Else
    If UserRecord.Level >= Option23 Then
       Strng="[N]ew messages"
       Call IO.O
    Else
       Strng="[*]ew messages"
       Call IO.O
    Endif
 End Select

 Select Case Option24
 Case 0
    Strng="[*]ead messages"
    Call IO.O
 Case -1
    Strng="[R]ead messages"
    Call IO.O
 Case Else
    If UserRecord.Level >= Option24 Then
       Strng="[R]ead messages"
       Call IO.O
    Else
       Strng="[*]ead messages"
       Call IO.O
    Endif
 End Select

 Select Case Option25
 Case 0
    Strng="[*]nlock mailbox"
    Call IO.O
 Case -1
    Strng="[U]nlock mailbox"
    Call IO.O
 Case Else
    If UserRecord.Level >= Option25 Then
       Strng="[U]nlock mailbox"
       Call IO.O
    Else
       Strng="[*]nlock mailbox"
       Call IO.O
    Endif
 End Select

 Strng="[Q]uit email"
 Call IO.O

 ' extended functions
 If optionx1=0 Then
    Return
 Endif
 Graphics.Off=False
 Strng="Extended mail functions:"
 Call IO.O
 Graphics.Off=True
 If Option1 Then
    VarQ=-1
    If Option2 Then
       If Sysop=False Then
          VarQ=0
       Endif
    Endif
    If VarQ Then
       Strng="[C]reate message base"
       Call IO.O
    Endif
 Endif
 Strng="[D]isplay message bases"
 Call IO.O
 Strng="[M]essbase search"
 Call IO.O
 Strng="[S]earch messages"
 Call IO.O
 VarZ=False
 If Sysop Then
    If Option4 Then
       VarZ=True
    Endif
 Else
    If Option8 Then
       VarZ=True
    Endif
 Endif
 If VarZ Then
    Strng="[W]Delete message base"
    Call IO.O
 Endif
 VarZ=False
 If Sysop Then
    If Option6 Then
       VarZ=True
    Endif
 Else
    If Option10 Then
       VarZ=True
    Endif
 Endif
 If VarZ Then
    Strng="[X]Edit message base"
    Call IO.O
 Endif
 VarZ=False
 If Sysop Then
    If Option5 Then
       VarZ=True
    Endif
 Else
    If Option9 Then
       VarZ=True
    Endif
 Endif
 If VarZ Then
    Strng="[Y]Undelete message base"
    Call IO.O
 Endif
 VarZ=False
 If Sysop Then
    If Option3 Then
       VarZ=True
    Endif
 Else
    If Option7 Then
       VarZ=True
    Endif
 Endif
 If VarZ Then
    Strng="[Z]Undelete message"
    Call IO.O
 Endif
 Return
Get.Config:
 Option20=-1:Option21=-1:Option22=-1:Option23=-1:Option24=-1:Option25=-1
 VarX=0
 VarZ=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[CMD086]" Then
       Do
          VarX=VarX+1
          If VarX>Options.Lines Then
             Return
          Endif
          Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
          If Ucase$(Var$)="[END]" Then
             Return
          Endif
          Var=Instr(Var$,"=")
          If Var Then
             Var2$=Ltrim$(Rtrim$(Left$(Var$,Var-1)))
             Var3$=Ltrim$(Rtrim$(Mid$(Var$,Var+1)))
             Select Case Lcase$(Var2$)
             Case "allow.extended.functions"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   optionx1=-1
                End Select
             Case "allow.create.base"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option1=-1
                End Select
             Case "only.sysops.create.base"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option2=-1
                End Select
             Case "sysops.can.undelete.message"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option3=-1
                End Select
             Case "sysops.can.delete.messbase"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option4=-1
                End Select
             Case "sysops.can.undelete.messbase"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option5=-1
                End Select
             Case "sysops.can.edit.messbase"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option6=-1
                End Select
             Case "user.can.undelete.message"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option7=-1
                End Select
             Case "user.can.delete.messbase"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option8=-1
                End Select
             Case "user.can.undelete.messbase"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option9=-1
                End Select
             Case "user.can.edit.messbase"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   option10=-1
                End Select

             Case "option1", "enter.mess"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   option20=0
                Case Else
                   If Int(Val(Var3$))>0 Then
                      option20=Int(Val(Var3$))
                   Endif
                End Select
             Case "option2", "kill.mess"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   option21=0
                Case Else
                   If Int(Val(Var3$))>0 Then
                      option21=Int(Val(Var3$))
                   Endif
                End Select
             Case "option3", "lock.mailbox"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   option22=0
                Case Else
                   If Int(Val(Var3$))>0 Then
                      option22=Int(Val(Var3$))
                   Endif
                End Select
             Case "option4", "new.mess"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   option23=0
                Case Else
                   If Int(Val(Var3$))>0 Then
                      option23=Int(Val(Var3$))
                   Endif
                End Select
             Case "option5", "read.mess"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   option24=0
                Case Else
                   If Int(Val(Var3$))>0 Then
                      option24=Int(Val(Var3$))
                   Endif
                End Select
             Case "option6", "unlock.mailbox"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   option25=0
                Case Else
                   If Int(Val(Var3$))>0 Then
                      option25=Int(Val(Var3$))
                   Endif
                End Select

             Case "always.allow.townmayor"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   If UserRecord.Flags And Special.Char1 Then
                       VarZ=-1
                   Endif
                End Select
             Case "always.allow.governor"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   If UserRecord.Flags And Special.Char2 Then
                       VarZ=-1
                   Endif
                End Select
             Case "always.allow.guildmaster"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   If UserRecord.Flags And Special.Char3 Then
                       VarZ=-1
                   Endif
                End Select

             Case "always.allow.sysop"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   If UserRecord.Flags And Special.Char4 Then
                       VarZ=-1
                   Endif
                End Select
             Case "always.allow.dm"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   If UserRecord.ClassType=DM Then
                       VarZ=-1
                   Endif
                End Select
             Case "always.allow.asstdm"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   If UserRecord.ClassType=AsstDM Then
                       VarZ=-1
                   Endif
                End Select
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
Error.Resume34:
 Erase Temp.ArrayS
 Exit Sub
Error.Trap34:
 Resume Error.Resume34
End Sub

Sub Create.Base
 On Local Error Goto Error.Trap35z
 Var = 1
 Do
    TempX$="BASE"+Mid$(Str$(Var),2)
    FileName=Data.Path4+TempX$+".TBL"
    If Dir$(FileName)=Nul Then
       FileName=Data.Path4+TempX$+".DAT"
       If Dir$(FileName)=Nul Then
          FileName=Data.Path4+TempX$+".NEW"
          If Dir$(FileName)=Nul Then
             Exit Do
          Endif
       Endif
    Endif
    Var = Var + 1
    If Var = 10000 Then ' base9999
       Strng="No available base filenames."
       Call IO.O
       Exit Sub
    Endif
 Loop
 FileName=Data.Path4+TempX$+".TBL"
 Close TempFile1
 Open FileName For Output As #TempFile1
 FileName=Data.Path4+TempX$+".DAT"
 Close TempFile1
 Open FileName For Output As #TempFile1
 FileName=Data.Path4+TempX$+".NEW"
 Close TempFile1
 Open FileName For Output As #TempFile1
 Close TempFile1
 Out3=Nul
 Do While Lost.Carrier=False
    Graphics.Off=True
    Strng="Message base topic name? "
    No.Input.Out=Nul
    Call IO.I
    Out2 = Ltrim$(Rtrim$(Out2))
    If Len(Out2) = 0 Then
       Strng="Base not created."
       Call IO.O
       Exit Sub
    Endif
    Out3=Out2
    Strng="Use '"+Out3+"' as message base topic(y/n/q)? "
    Line.Length=1
    No.Input.Out="Y"
    Call IO.I
    If Ucase$(Out2)="Y" Then
       Exit Do
    Endif
    If Ucase$(Out2)="Q" Then
       Exit Sub
    Endif
 Loop
 If Out3=Nul Then
    Out3="<none>"
 Endif
 Temp!=Lof(MessBaseFile)/MessBaseRecLen+1!
 MessageBaseRecord.BaseDeleted=False
 MessageBaseRecord.BaseMessName=Out3
 MessageBaseRecord.BaseFileName=TempX$
 MessageBaseRecord.BaseType=Public.Base
 Call Write.Record(MessBaseFile,Temp!)
 Strng="Base"+Str$(Temp!)+":'"+Out3+"' created."
 Call IO.O
Error.Resume35z:
 Exit Sub
Error.Trap35z:
 Resume Error.Resume35z
End Sub

Sub Delete.Messbase
 On Local Error Goto Error.Trap35z2
 If Temp!>2! Then
    Call Read.Record(MessBaseFile,Temp!-2!)
    If MessageBaseRecord.BaseDeleted=True Then
       Strng="Message base already deleted."
       Call IO.O
    Else
       MessageBaseRecord.BaseDeleted=True
       Call Write.Record(MessBaseFile,Temp!-2!)
       Strng="Message base deleted."
       Call IO.O
    Endif
 Else
    If Temp!=1! Then
       Strng="Cannot delete public messbase."
    Else
       Strng="Cannot delete private messbase."
    Endif
    Call IO.O
 Endif
Error.Resume35z2:
 Exit Sub
Error.Trap35z2:
 Resume Error.Resume35z2
End Sub

Sub Display.Messbases
 On Local Error Goto Error.Trap35z2a
 Strng="Message bases:"
 Call IO.O
 Graphics.Off=True
 Strng=Mask$+"1:Public, Type: (public)"
 Call IO.O
 Strng=Mask$+"2:Private, Type: (private)"
 Call IO.O
 Temp1=2
 Allow.Break=True
 Break=False
 Continuous=False
 For Temp!=1! To Lof(MessBaseFile)/MessBaseRecLen
    Call Read.Record(MessBaseFile,Temp!)
    Out2=MessageBaseRecord.BaseMessName
    Out2=Rtrim$(Out2)
    Out2=Lcase$(Out2)
    If Out2=Nul Then
       Out2="<none>"
    Endif
    Mid$(Out2,1,1)=Ucase$(Mid$(Out2,1,1))
    Strng=Mask$+Form$(Cdbl(Temp!+2!))+":"+Out2+", Type: "
    If MessageBaseRecord.BaseDeleted Then
       Strng=Strng+"(deleted)"
    Else
       If MessageBaseRecord.BaseType And Public.Base Then
          Strng=Strng+"(public) "
       Endif
       If MessageBaseRecord.BaseType And Private.Base Then
          Strng=Strng+"(private) "
       Endif
       If MessageBaseRecord.BaseType And DM.Base Then
          Strng=Strng+"(DMs only) "
       Endif
       If MessageBaseRecord.BaseType And Sysop.Base Then
          Strng=Strng+"(Sysops only) "
       Endif
       If MessageBaseRecord.BaseType And TownMayor.Base Then
          Strng=Strng+"(Town Mayor) "
       Endif
       If MessageBaseRecord.BaseType And Governor.Base Then
          Strng=Strng+"(Governor) "
       Endif
       If MessageBaseRecord.BaseType And GuildMaster.Base Then
          Strng=Strng+"(Guild Master) "
       Endif
       If MessageBaseRecord.BaseType And 128 Then
          Strng=Strng+"(Assistant DM) "
       Endif
    Endif
    Strng=Rtrim$(Strng)
    Call IO.O
    If Break Then
       Exit For
    Endif
    Temp1=Temp1+1
    If Temp1>=User.Pagelength-2 Then
       Temp1=False
       If Continuous=False Then
          Call More.Prompt
          If No Or Quit Then
             Exit For
          Endif
       Endif
    Endif
 Next
 Allow.Break=False
 Break=False
 Graphics.Off=False
Error.Resume35z2a:
 Exit Sub
Error.Trap35z2a:
 Resume Error.Resume35z2a
End Sub

Sub Undelete.Messbase
 On Local Error Goto Error.Trap35z3
 Strng="Deleted message bases:"
 Call IO.O
 Temp1=0
 Temp2=0
 Allow.Break=True
 Break=False
 Continuous=False
 For Temp!=1! To Lof(MessBaseFile)/MessBaseRecLen
    Call Read.Record(MessBaseFile,Temp!)
    Out2=MessageBaseRecord.BaseMessName
    Out2=Rtrim$(Out2)
    Out2=Lcase$(Out2)
    If MessageBaseRecord.BaseDeleted Then
       If Out2=Nul Then
          Out2="<none>"
       Endif
       Mid$(Out2,1,1)=Ucase$(Mid$(Out2,1,1))
       Strng=Mask$+Form$(Cdbl(Temp!+2!))+": "+Out2
       Call IO.O
       Temp2=-1
       If Break Then
          Exit For
       Endif
       Temp1=Temp1+1
       If Temp1>=User.Pagelength-2 Then
          Temp1=False
          If Continuous=False Then
             Call More.Prompt
             If No Or Quit Then
                Exit For
             Endif
          Endif
       Endif
    Endif
 Next
 Allow.Break=False
 Break=False
 Graphics.Off=False
 If Temp2=0 Then
    Strng="There are no messbases to undelete."
    Call IO.O
    Exit Sub
 Endif
 Strng="Enter message base number(1-"+ _
 Form$(Cdbl(Lof(MessBaseFile)/MessBaseRecLen+2!))+")? "
 Call IO.I
 If Out2=Nul Then
    Exit Sub
 Endif
 Temp!=Int(Val(Out2))
 If Temp!<=SFalse Or Temp!>Lof(MessBaseFile)/MessBaseRecLen+2! Then
    Strng=Range$
    Call IO.O
    Exit Sub
 Endif
 Temp!=Int(Val(Out2))
 Select Case Temp!
 Case 1!
    Strng="Can't undelete public messbase."
    Call IO.O
    Exit Sub
 Case 2!
    Strng="Can't undelete private messbase."
    Call IO.O
    Exit Sub
 Case Else
    Call Read.Record(MessBaseFile,Temp!-2!)
    If MessageBaseRecord.BaseDeleted=False Then
       Strng="Message base not deleted."
    Else
       MessageBaseRecord.BaseDeleted=False
       Call Write.Record(MessBaseFile,Temp!-2!)
       Strng="Message base undeleted."
    Endif
    Call IO.O
 End Select
Error.Resume35z3:
 Exit Sub
Error.Trap35z3:
 Resume Error.Resume35z3
End Sub

Sub Edit.Messbase
 On Local Error Goto Error.Trap35z3a
 If Temp!=1! Then
    Strng="Public messbase."
    Call IO.O
    Exit Sub
 Endif
 If Temp!=2! Then
    Strng="Private messbase."
    Call IO.O
    Exit Sub
 Endif
 If Temp!>2! Then
    Call Read.Record(MessBaseFile,Temp!-2!)
    Do While Lost.Carrier=False
       Graphics.Off=True
       Strng=Rtrim$(MessageBaseRecord.BaseMessName)
       If Len(Strng) Then
          Strng=Lcase$(Strng)
          Mid$(Strng,1)=Ucase$(Mid$(Strng,1,1))
       Endif
       Strng="[A]BaseMessName: "+Strng
       Call IO.O
       Strng="[B]BaseType "
       If MessageBaseRecord.BaseType And Public.Base Then
          Strng=Strng+"(public) "
       Endif
       If MessageBaseRecord.BaseType And Private.Base Then
          Strng=Strng+"(private) "
       Endif
       If MessageBaseRecord.BaseType And DM.Base Then
          Strng=Strng+"(DMs only) "
       Endif
       If MessageBaseRecord.BaseType And Sysop.Base Then
          Strng=Strng+"(Sysops only) "
       Endif
       If MessageBaseRecord.BaseType And TownMayor.Base Then
          Strng=Strng+"(Town Mayor) "
       Endif
       If MessageBaseRecord.BaseType And Governor.Base Then
          Strng=Strng+"(Governor) "
       Endif
       If MessageBaseRecord.BaseType And GuildMaster.Base Then
          Strng=Strng+"(Guild Master) "
       Endif
       If MessageBaseRecord.BaseType And 128 Then
          Strng=Strng+"(Assistant DM) "
       Endif
       Call IO.O
       Graphics.Off=False
       Strng="Edit messbase(A, B, Q to Quit)? "
       No.Input.Out="Q"
       Graphics.Off=False
       Call IO.I
       Select Case Ucase$(Out2)
       Case "A"
          Strng="Message base name? "
          Call IO.I
          If Len(Out2) Then
             MessageBaseRecord.BaseMessName=Ucase$(Out2)
             Call Write.Record(MessBaseFile,Temp!-2!)
          Endif
       Case "B"
          Do While Lost.Carrier=False
             Graphics.Off=True
             Strng="[1]public "
             If MessageBaseRecord.BaseType And 1 Then
                Strng=Strng+"(enabled)"
             Else
                Strng=Strng+"(disabled)"
             Endif
             Call IO.O
             Strng="[2]private "
             If MessageBaseRecord.BaseType And 2 Then
                Strng=Strng+"(enabled)"
             Else
                Strng=Strng+"(disabled)"
             Endif
             Call IO.O
             Strng="[3]DMs "
             If MessageBaseRecord.BaseType And 4 Then
                Strng=Strng+"(enabled)"
             Else
                Strng=Strng+"(disabled)"
             Endif
             Call IO.O
             Strng="[4]Sysops "
             If MessageBaseRecord.BaseType And 8 Then
                Strng=Strng+"(enabled)"
             Else
                Strng=Strng+"(disabled)"
             Endif
             Call IO.O
             Strng="[5]Town Mayor "
             If MessageBaseRecord.BaseType And 16 Then
                Strng=Strng+"(enabled)"
             Else
                Strng=Strng+"(disabled)"
             Endif
             Call IO.O
             Strng="[6]Governor "
             If MessageBaseRecord.BaseType And 32 Then
                Strng=Strng+"(enabled)"
             Else
                Strng=Strng+"(disabled)"
             Endif
             Call IO.O
             Strng="[7]Guild Master "
             If MessageBaseRecord.BaseType And 64 Then
                Strng=Strng+"(enabled)"
             Else
                Strng=Strng+"(disabled)"
             Endif
             Call IO.O
             Strng="[8]Assistant DM "
             If MessageBaseRecord.BaseType And 128 Then
                Strng=Strng+"(enabled)"
             Else
                Strng=Strng+"(disabled)"
             Endif
             Call IO.O
             Graphics.Off=False
             Strng="Message base type(1-8, 9=Clear, 10=All, Q to Quit)? "
             No.Input.Out="q"
             Line.Length=1
             Call IO.I
             If Lcase$(Out2)="q" Then
                Exit Do
             Endif
             If Len(Out2) Then
                ' flip basetype bit
                Var=MessageBaseRecord.BaseType
                Var2=Int(Val(Out2))
                Select Case Var2
                Case 1 To 8
                   Var=Var Xor 2^(Var2-1)
                Case 9
                   Var=0
                Case 10
                   Var=255
                Case Else
                   Strng="Unknown classtype."
                   Call IO.O
                End Select
                MessageBaseRecord.BaseType=Var
                Call Write.Record(MessBaseFile,Temp!-2!)
             Endif
          Loop
       Case "Q"
          Exit Do
       End Select
    Loop
 Else
    Strng=Range$
    Call IO.O
 Endif
Error.Resume35z3a:
 Exit Sub
Error.Trap35z3a:
 Resume Error.Resume35z3a
End Sub

Sub Enter.Message
 On Local Error Goto Error.Trap36
 Do While Lost.Carrier=False
    Graphics.Off=True
    Private.Message=False
    Strng="Message to codename(Press "+Enter$+" for ALL)"
    Call IO.O
    Carriage.Return=-1
    Strng="Message to?[                              ]"
    Call IO.O
    Call Back.Space2(31)
    Carriage.Return=-2
    Strng=""
    Line.Length=30
    Call IO.I
    Carriage.Return=0
    Message.To=Ucase$(Out2)
    If Out2=Nul Then
       Exit Do
    Endif
    For Temp.User.Index=1! To Lof(UserFile2)/UserRecLen
       Call Read.Record(UserFile2,Temp.User.Index)
       Strng=UserRecord2.CodeName
       Strng=Rtrim$(Strng)
       Strng=Ucase$(Strng)
       If Message.To=Strng Then
          If User.Index<>Temp.User.Index Then
             If (UserRecord.Flags And Locked.User)=False Then
                Call PrivateMessage
                Exit Do
             Endif
          Endif
       Endif
    Next
    Strng="There is no such user."
    Call IO.O
 Loop
 Do While Lost.Carrier=False
    Carriage.Return=-1
    Strng="Subject topic?[                    ]"
    Call IO.O
    Call Back.Space2(21)
    Carriage.Return=-2
    Strng=""
    Line.Length=20
    Call IO.I
    Carriage.Return=0
    Subject=Lcase$(Out2)
    If Subject<>Nul Then
       Strng="Use subject: "+Chr$(34)+Subject+Chr$(34)+"(y/n)? "
       Line.Length=1
       No.Input.Out="Y"
       Call IO.I
       If Ucase$(Out2)="Y" Then
          Exit Do
       Endif
    Else
       Strng="Abort message(y/n)? "
       Line.Length=1
       No.Input.Out="N"
       Call IO.I
       If Ucase$(Out2)="Y" Then
          Exit Sub
       Endif
    Endif
 Loop
 Message.Reply=False
 Call Write.Message(VarZ)
Error.Resume36:
 Exit Sub
Error.Trap36:
 Resume Error.Resume36
End Sub

Sub Write.Message(VarZ)
 On Local Error Goto Error.Trap37
 Strng="Enter message. Maximum 19 lines."
 Call IO.O
 VarZ=False
 Message.Length=False
 Do While Lost.Carrier=False
    If Message.Length<19 Then
       Strng="Press "+Enter$+" on a blank line to edit."
       Call IO.O
       Do While Lost.Carrier=False
          Graphics.Off=True
          If Message.Length<19 Then
             Word.Wrap=True
          Else
             Word.Wrap=False
          Endif
          Strng="?"
          Call IO.I
          If No.Input Then
             Exit Do
          Endif
          Message.Length=Message.Length+1
          Out2=Rtrim$(Out2)
          Out2=Left$(Out2,80)
          Temp.ArrayS(Message.Length)=Out2
          If Message.Length=19 Then
             Strng="Message buffer full."
             Call IO.O
             Exit Do
          Endif
       Loop
    Endif
    ' edit message text menu
    Temp0=19
    Call Edit.Message(VarX)
    If VarX=True Then ' continue
       If Message.Length=19 Then
          Strng="Message buffer full."
       Else
          Strng="Continue editing."
       Endif
       Call IO.O
    Endif
    If VarX=False Then ' abort
       Exit Do
    Endif
    If VarX=1 Then ' store
       Call Store.Message
       VarZ=True
       Exit Do
    Endif
 Loop
Error.Resume37:
 Exit Sub
Error.Trap37:
 Resume Error.Resume37
End Sub

Sub Lock.Mailbox(Var)
 On Local Error Goto Error.Trap38
 If Var Then
    If UserRecord.Flags And Locked.User Then
       Strng="Mailbox already locked."
    Else
       Strng="Mailbox locked."
       UserRecord.Flags=UserRecord.Flags Or Locked.User
    Endif
 Else
    If (UserRecord.Flags And Locked.User)=0 Then
       Strng="Mailbox already unlocked."
    Else
       Strng="Mailbox unlocked."
       UserRecord.Flags=UserRecord.Flags And Not Locked.User
    Endif
 Endif
 Call Write.Record(UserFile,User.Index)
 Call IO.O
Error.Resume38:
 Exit Sub
Error.Trap38:
 Resume Error.Resume38
End Sub

Sub Kill.Message
 On Local Error Goto Error.Trap39
 If Lof(TableFile)/TableRecLen=0! Then
    Strng="No messages to delete."
    Call IO.O
    Exit Sub
 Endif
 Strng="Enter message number to delete(1-"+ _
 Form$(Cdbl(Lof(TableFile)/TableRecLen))+")?"
 Call IO.I
 If Out2=Nul Then
    Exit Sub
 Endif
 Temp!=Val(Out2)
 If Temp!<=SFalse Or Temp!>Lof(TableFile)/TableRecLen Then
    Strng=Range$
    Call IO.O
    Exit Sub
 Endif
 Call Read.Record(TableFile,Temp!)
 Strng=UserRecord.CodeName
 Strng=Rtrim$(Strng)
 Strng=Ucase$(Strng)
 Out2=TableRecord.To
 Out2=Rtrim$(Out2)
 Out2=Ucase$(Out2)
 If Strng<>Out2 Then
    If Sysop=False Then
       Strng="Message "+Form$(Cdbl(Temp!))+" is not a private message to you."
       Call IO.O
       Exit Sub
    Endif
    If TableRecord.Private=False Then
       Strng="Message "+Form$(Cdbl(Temp!))+" is not a private message to you."
       Call IO.O
       Exit Sub
    Endif
 Endif
 If TableRecord.Killed Then
    Strng="Message "+Form$(Cdbl(Temp!))+" is already deleted."
    Call IO.O
    Exit Sub
 Endif
 TableRecord.Killed=True
 Call Write.Record(TableFile,Temp!)
 Strng="Message "+Form$(Cdbl(Temp!))+" deleted."
 Call IO.O
Error.Resume39:
 Exit Sub
Error.Trap39:
 Resume Error.Resume39
End Sub

Sub Undelete.Message
 On Local Error Goto Error.Trap39a
 If Lof(TableFile)/TableRecLen=0! Then
    Strng="No messages to undelete."
    Call IO.O
    Exit Sub
 Endif
 Strng="Enter message number to undelete(1-"+ _
 Form$(Cdbl(Lof(TableFile)/TableRecLen))+")?"
 Call IO.I
 If Out2=Nul Then
    Exit Sub
 Endif
 Temp!=Int(Val(Out2))
 If Temp!<=SFalse Or Temp!>Lof(TableFile)/TableRecLen Then
    Strng=Range$
    Call IO.O
    Exit Sub
 Endif
 Call Read.Record(TableFile,Temp!)
 If TableRecord.Killed=False Then
    Strng="Message "+Form$(Cdbl(Temp!))+" is not deleted."
    Call IO.O
    Exit Sub
 Endif
 TableRecord.Killed=False
 Call Write.Record(TableFile,Temp!)
 Strng="Message "+Form$(Cdbl(Temp!))+" undeleted."
 Call IO.O
Error.Resume39a:
 Exit Sub
Error.Trap39a:
 Resume Error.Resume39a
End Sub

Sub Read.Message(Var!)
 On Local Error Goto Error.Trap40
 Call Read.Record(TableFile,Var!)
 Strng=UserRecord.CodeName
 Strng=Rtrim$(Strng)
 Strng=Ucase$(Strng)
 Select Case Message.Base.Number
 Case 1
    Var1=False
 Case 2
    Var1=True
 Case Else
    Call Read.Record(MessBaseFile,Message.Base.Number-2!)
    If MessageBaseRecord.BaseType And Private.Base Then
       Var1=True
    Endif
 End Select
 If Var1 Then
    Out2=TableRecord.To
    Out2=Rtrim$(Out2)
    Out2=Ucase$(Out2)
    If Out2=Nul Or Strng=Out2 Then
       Var1=False
    Endif
 Endif
 If Var1 Then
    If Sysop=False Then
       Strng="Message #"+Form$(Cdbl(Var!))+" is private."
       Call IO.O
       Exit Sub
   Endif
 Endif
 Graphics.Off=True
 Call Message.Header(Var!)
 Allow.Break=True
 Break=False
 TempS!=TableRecord.Start
 TempT!=TempS!+Csng(TableRecord.Length)-1!
 For Var2!=TempS! To TempT!
    Call Read.Record(MessageFile,Var2!)
    Strng=BufferRecord.Buffer
    Call Crypto(Strng)
    Strng=Rtrim$(Strng)
    Call Convert.String
    Call Convert.ANSI(True,VarQ,VarR)
    Graphics.On=True
    Call IO.O
    Graphics.On=False
    If Break Then
       Exit For
    Endif
 Next
 Allow.Break=False
 Break=False
Error.Resume40:
 Exit Sub
Error.Trap40:
 Resume Error.Resume40
End Sub

Sub Read.Messages
 On Local Error Goto Error.Trap41
 Temp2$=UserRecord.CodeName
 Temp2$=Rtrim$(Temp2$)
 Temp2$=Ucase$(Temp2$)
 Graphics.Off=False
 No.Input.Out="1"
 VarX!=Lof(TableFile)/TableRecLen
 If VarX!=SFalse Then
    Strng="No messages in this message base."
    Call IO.O
    Exit Sub
 Endif
 VarX=False
 Do While Lost.Carrier=False
    Graphics.Off=False
    Line.Length=1
    No.Input.Out="N"
    Strng="Read only messages addressed to you(y/n)? "
    Call IO.I
    If Ucase$(Out2)="Y" Then
       VarX=True
       Exit Do
    Endif
    If Ucase$(Out2)="N" Then
       Exit Do
    Endif
 Loop
 No.Input.Out="1"
 Strng="Starting message number(1-"+Form$(Cdbl(VarX!))+")? "
 Call IO.I
 If Out2=Nul Then
    Exit Sub
 Endif
 Var3!=Int(Val(Out2))
 If Var3!<=SFalse Or Var3!>VarX! Then
    Strng=Range$
    Call IO.O
    Exit Sub
 Endif
 Do While Lost.Carrier=False
    If Var3!>Lof(TableFile)/TableRecLen Then
       Exit Do
    Endif
    Do While Lost.Carrier=False
       Call Read.Record(TableFile,Var3!)
       Out2=TableRecord.To
       Out2=Rtrim$(Out2)
       Out2=Ucase$(Out2)
       If VarX Then
          If Var3!>Lof(TableFile)/TableRecLen Then
             Strng="End of messages."
             Call IO.O
             Exit Sub
          Endif
          If Out2=Temp2$ Then
             Call Read.Message(Var3!)
             Call Read.Record(TableFile,Var3!)
             TableRecord.Received=True
             TableRecord.TimesRead=TableRecord.TimesRead+1#
             Call Write.Record(TableFile,Var3!)
             Exit Do
          Endif
          Var3!=Var3!+1!
       Else
          If TableRecord.Private And Out2<>Temp2$ Then
             If Sysop=False Then
                Graphics.Off=True
                Strng="Message #"+Form$(Cdbl(Var3!))+" is private."
                Call IO.O
                Exit Do
             Endif
          Endif
          If TableRecord.Killed Then
             Graphics.Off=True
             Strng="Message #"+Form$(Cdbl(Var3!))+" was deleted."
             Call IO.O
             If Sysop=False Then
                Exit Do
             Endif
             VarX=0
             Do While Lost.Carrier=False
                Line.Length=1
                No.Input.Out="N"
                Strng="Read anyway(y/n)? "
                Call IO.I
                If Ucase$(Out2)="Y" Then
                   Exit Do
                Endif
                If Ucase$(Out2)="N" Then
                   VarX=-1
                   Exit Do
                Endif
             Loop
             If VarX Then
                Exit Do
             Endif
          Endif
          Call Read.Message(Var3!)
          Call Read.Record(TableFile,Var3!)
          TableRecord.Received=True
          TableRecord.TimesRead=TableRecord.TimesRead+1#
          Call Write.Record(TableFile,Var3!)
          Exit Do
       Endif
    Loop
    Graphics.Off=False
    Strng="Read more (y)es/(n)o/(r)eply/(t)hread/(+/-), msg number? "
    No.Input.Out="y"
    Call IO.I
    Select Case Ucase$(Out2)
    Case "N", "Q"
       Exit Do
    Case "R"
       Private.Message=False
       Call PrivateMessage
       Message.Reply=True
       Message.Thread=Var3!
       Message.To=TableRecord.From
       Subject=TableRecord.Subject
       Strng="Enter message reply."
       Call IO.O
       Call Write.Message(VarZ)
       Call Read.Record(TableFile,Var3!)
       If VarZ Then
          TableRecord.Reply=True
          Call Write.Record(TableFile,Var3!)
       Endif
       Var3!=Var3!-1!
    Case "T"
       Strng="Direction:(b)ackward/(f)orward/(s)earch? "
       Line.Length=1
       No.Input.Out="f"
       Call IO.I
       Select Case Ucase$(Out2)
       Case "B" ' backward
          If TableRecord.Thread=SFalse Then
             Strng="Message has no backward reply thread."
             Call IO.O
             Call More.Prompt
             Var3!=Var3!-1!
          Else
             Var3!=TableRecord.Thread-1!
          Endif
       Case "F" ' forward
          For TempS!=Var3! To Lof(TableFile)/TableRecLen
             Call Read.Record(TableFile,TempS!)
             If TableRecord.Thread=Var3! Then
                Var3!=TempS!-1!
                Exit For
             Endif
          Next
          If TempS!>Lof(TableFile)/TableRecLen Then
             Strng="Message has no forward thread."
             Call IO.O
             Call More.Prompt
             Var3!=Var3!-1!
          Endif
       Case "S" ' search
          For TempS!=Var3! To Lof(TableFile)/TableRecLen
             Call Read.Record(TableFile,TempS!)
             If TableRecord.Thread=Var3! Then
                Call Sub.Header(TempS!)
                Graphics.Off=False
                Do While Lost.Carrier=False
                   Strng="Message thread:(c)ontinue search/(r)ead message? "
                   Line.Length=1
                   No.Input.Out="r"
                   Call IO.I
                   If Ucase$(Out2)="C" Then
                      Exit Do
                   Endif
                   If Ucase$(Out2)="R" Then
                      Var3!=TempS!-1!
                      Exit For
                   Endif
                Loop
             Endif
          Next
          If TempS!>Lof(TableFile)/TableRecLen Then
             Strng="There are no more forward threads."
             Call IO.O
             Call More.Prompt
             Var3!=Var3!-1!
          Endif
       End Select
    Case "-"
       Var3!=Var3!-2!
       If Var3!<SFalse Then
          Var3!=SFalse
       Endif
    Case "+"
       ' nul
    Case Else
       Temp1!=Int(Val(Out2))
       If Temp1!>SFalse And Temp1!<=Lof(TableFile)/TableRecLen Then
          Var3!=Temp1!-1!
       Endif
    End Select
    Var3!=Var3!+1!
 Loop
 Strng="End of messages."
 Call IO.O
Error.Resume41:
 Exit Sub
Error.Trap41:
 Resume Error.Resume41
End Sub

Sub Search.Messages
 On Local Error Goto Error.Trap41a
 VarX!=Lof(TableFile)/TableRecLen
 If VarX!=SFalse Then
    Strng="No messages in this message base."
    Call IO.O
    Exit Sub
 Endif
 Strng="Starting message number(1-"+Form$(Cdbl(VarX!))+")? "
 No.Input.Out="1"
 Call IO.I
 If Out2=Nul Then
    Exit Sub
 Endif
 Var3!=Int(Val(Out2))
 If Var3!<=SFalse Or Var3!>VarX! Then
    Strng=Range$
    Call IO.O
    Exit Sub
 Endif
 Strng="Message text(?,* allowed): "
 Call IO.I
 If Out2=Nul Then
    Exit Sub
 Endif
 Var3$=Out2
 Do While Lost.Carrier=False
    Line.Length=1
    No.Input.Out="N"
    Strng="Case sensitive(y/n)? "
    Call IO.I
    If Ucase$(Out2)="Y" Then
       TmpS=-1
       Exit Do
    Endif
    If Ucase$(Out2)="N" Then
       TmpS=0
       Exit Do
    Endif
 Loop
 TmpX=False
 Allow.Break=True
 Break=False
 Temp1=False
 Continuous=False
 Do While Lost.Carrier=False
    If Var3!>Lof(TableFile)/TableRecLen Then
       Exit Do
    Endif
    Call Read.Record(TableFile,Var3!)
    If TableRecord.Killed=False Then
       VarL=False
       TempS!=TableRecord.Start
       TempT!=TempS!+Csng(TableRecord.Length)-1!
       For Var2!=TempS! To TempT!
          VarL=VarL+1
          Call Read.Record(MessageFile,Var2!)
          Strng=BufferRecord.Buffer
          Call Crypto(Strng)
          Strng=Rtrim$(Strng)
          ' see if Var3$ matches in Strng case-sensitive
          V1$=Strng
          V2$=Var3$
          If Len(V1$)>0 And Len(V2$)>0 Then
             Call InstrSUB1(VarX,Var3$,TmpS)
             If VarX Then
                TmpX=True
                Graphics.On=True
                Strng="Message: "+Form$(Cdbl(Var3!))+", Line:"+Str$(VarL)+", position"+Str$(VarX)+"."
                Call IO.O
             Endif
             Graphics.On=False
             Temp1=Temp1+1
             If Temp1>=User.Pagelength-2 Then
                Temp1=False
                If Continuous=False Then
                   Call More.Prompt
                   If No Or Quit Then
                      Exit Do
                   Endif
                Endif
             Endif
          Endif
          If Break Then
             Exit Do
          Endif
          If Lost.Carrier Then
             Exit Do
          Endif
       Next
    Endif
    Var3!=Var3!+1!
 Loop
 Allow.Break=False
 Break=False
 If TmpX=False Then
    Strng="No text found."
    Call IO.O
 Else
    If Temp1 Then
       Call More.Prompt
    Endif
 Endif
 Exit Sub
Error.Resume41a:
 Exit Sub
Error.Trap41a:
 Resume Error.Resume41a
End Sub

Sub Search.Messbases
 On Local Error Goto Error.Trap41b
 Strng="Messbase name text(?,* allowed): "
 Call IO.I
 Var3$=Out2
 If Var3$=Nul Then
    Exit Sub
 Endif
 Var3$=Lcase$(Var3$)
 Temp1=False
 TmpX=False
 Strng="public"
 Call InstrSUB1(VarX,Var3$,0)
 If VarX Then
    If Temp1=0 Then
       Strng="Message bases:"
       Call IO.O
       Graphics.Off=True
    Endif
    Strng="Messbase#1: Public"
    Call IO.O
    Temp1=Temp1+1
    TmpX=True
 Endif
 Strng="private"
 Call InstrSUB1(VarX,Var3$,0)
 If VarX Then
    If Temp1=0 Then
       Strng="Message bases:"
       Call IO.O
       Graphics.Off=True
    Endif
    Strng="Messbase#2: Private"
    Call IO.O
    Temp1=Temp1+1
    TmpX=True
 Endif
 Allow.Break=True
 Break=False
 Continuous=False
 For Temp!=1! To Lof(MessBaseFile)/MessBaseRecLen
    Call Read.Record(MessBaseFile,Temp!)
    If MessageBaseRecord.BaseDeleted=False Then
       Out3=MessageBaseRecord.BaseMessName
       Out3=Rtrim$(Out3)
       Out3=Lcase$(Out3)
       If Out3<>Nul Then
          Strng=Out3
          Call InstrSUB1(VarX,Var3$,0)
          If VarX Then
             If Temp1=0 Then
                Strng="Message bases:"
                Call IO.O
                Graphics.Off=True
             Endif
             TmpX=True
             Mid$(Out3,1,1)=Ucase$(Mid$(Out3,1,1))
             Strng="Messbase#"+Form$(Cdbl(Temp!+2!))+": "+Out3
             Call IO.O
             If Break Then
                Exit For
             Endif
             Temp1=Temp1+1
             If Temp1>=User.Pagelength-2 Then
                Temp1=False
                If Continuous=False Then
                   Call More.Prompt
                   If No Or Quit Then
                      Exit For
                   Endif
                Endif
             Endif
          Endif
       Endif
    Endif
 Next
 Allow.Break=False
 Break=False
 Graphics.Off=False
 If TmpX=False Then
    Strng="No bases found."
    Call IO.O
 Else
    If Temp1 Then
       Call More.Prompt
    Endif
 Endif
Error.Resume41b:
 Exit Sub
Error.Trap41b:
 Resume Error.Resume41b
End Sub

Sub New.Messages
 On Local Error Goto Error.Trap42
 VarX=1
 Do While Lost.Carrier=False
    Graphics.Off=False
    Strng="Read new messages menu:"
    Call IO.O
    Graphics.Off=True
    Strng="(1)Public messages addressed to you."
    Call IO.O
    Strng="(2)Public messages addressed to ALL."
    Call IO.O
    Strng="(3)Private messages addressed to you."
    Call IO.O
    Graphics.Off=False
    Strng="Enter option(1,2,3,Q to Quit)? "
    Call IO.I
    If Ucase$(Out2)="Q" Then
       Exit Sub
    Endif
    VarX=Int(Val(Out2))
    If VarX>=1 And VarX<=3 Then
       Exit Do
    Endif
 Loop
 Message.Base.Name=Rtrim$(Message.Base.Name)
 Close #NewFile
 Select Case VarX
 Case 1
    FileName=Data.Path4+Message.Base.Name+".NEW" ' public message to user
 Case 2
    FileName=Data.Path4+Message.Base.Name+".NW2" ' public messages
 Case 3
    FileName=Data.Path4+Message.Base.Name+".NW3" ' private message to user
 End Select
 Open FileName For Random Shared As #NewFile Len=NewMessRecLen
 Var!=Lof(NewFile)/NewMessRecLen
 If User.Index>Var! Then
    For Var1!=Var!+1! To User.Index
       NewMessages.LastMessage=SFalse
       Call Write.Record(NewFile,Var1!)
    Next
 Endif
 Call Read.Record(NewFile,User.Index)
 TempM!=NewMessages.LastMessage
 If TempM!<SFalse Then
    TempM!=SFalse
 Endif
 If TempM!>=Lof(TableFile)/TableRecLen Then
    Graphics.Off=True
    Strng="Sorry, there are no new messages."
    Call IO.O
    Exit Sub
 Endif
 Do While Lost.Carrier=False
    TempM!=TempM!+1! ' increase message pointer
    Call Read.Record(TableFile,TempM!)
    Out2=Ucase$(Rtrim$(TableRecord.To))
    Strng2=Ucase$(Rtrim$(UserRecord.CodeName))
    Var2=True
    Select Case VarX
    Case 1 ' public message to user
       If TableRecord.Private Then
          Var2=False
       Else
          If Out2<>Strng2 Then
             Var2=False
          Endif
       Endif
    Case 2 ' public message to ALL
       If TableRecord.Private Then
          Var2=False
       Else
          If Out2<>"ALL" Then
             Var2=False
          Endif
       Endif
    Case 3 ' private message to user
       If TableRecord.Private=False Then
          Var2=False
       Else
          If Out2<>Strng2 Then
             Var2=False
          Endif
       Endif
    End Select
    ' store last message read pointer
    If TempM!>NewMessages.LastMessage Then
       NewMessages.LastMessage=TempM!
       Call Write.Record(NewFile,User.Index)
    Endif
    If TableRecord.Killed Then
       Var2=False
    Endif
    If Var2 Then
       Call Read.Message(TempM!)
       TableRecord.Received=True
       TableRecord.TimesRead=TableRecord.TimesRead+1#
       Call Write.Record(TableFile,TempM!)
       Graphics.Off=False
       Strng="Read more (y)es/(n)o/(r)eply/(+/-)? "
       No.Input.Out="Y"
       Call IO.I
       Select Case Ucase$(Out2)
       Case "R" ' reply
          Private.Message=False
          Call PrivateMessage
          Message.Reply=True
          Message.Thread=TempM!
          Message.To=TableRecord.From
          Subject=TableRecord.Subject
          Strng="Enter message reply."
          Call IO.O
          Call Write.Message(VarZ)
          Call Read.Record(TableFile,TempM!)
          If VarZ Then
             TableRecord.Reply=True
             Call Write.Record(TableFile,TempM!)
          Endif
          TempM!=TempM!-1!
       Case "-" ' backup one message
          TempM!=TempM!-2!
          If TempM!<SFalse Then
             TempM!=SFalse
          Endif
       Case "+"
          ' default one forward
       Case "N", "Q" ' quit read loop
          Exit Do
       End Select
    Endif
    ' compare pointer
    If TempM!>=Lof(TableFile)/TableRecLen Then
       Exit Do
    Endif
 Loop
 Graphics.Off=True
 Strng="End of new messages."
 Call IO.O
Error.Resume42:
 Exit Sub
Error.Trap42:
 Resume Error.Resume42
End Sub

Sub Select.Base(Var,VarQ)
 On Local Error Goto Error.Trap43
 Strng="Select message base:"
 Call IO.O
 Graphics.Off=True
 Strng=Mask$+"1:Public, Type: (public)"
 Call IO.O
 Strng=Mask$+"2:Private, Type: (private)"
 Call IO.O
 Temp1=2
 Allow.Break=True
 Break=False
 Continuous=False
 For Temp!=1! To Lof(MessBaseFile)/MessBaseRecLen
    Call Read.Record(MessBaseFile,Temp!)
    Out2=MessageBaseRecord.BaseMessName
    Out2=Rtrim$(Out2)
    Out2=Lcase$(Out2)
    If Out2=Nul Then
       Out2="<none>"
    Endif
    If MessageBaseRecord.BaseDeleted=False Then
       Mid$(Out2,1,1)=Ucase$(Mid$(Out2,1,1))
       Strng=Mask$+Form$(Cdbl(Temp!+2!))+":"+Out2+", Type: "
       If MessageBaseRecord.BaseType And Public.Base Then
          Strng=Strng+"(public) "
       Endif
       If MessageBaseRecord.BaseType And Private.Base Then
          Strng=Strng+"(private) "
       Endif
       If MessageBaseRecord.BaseType And DM.Base Then
          Strng=Strng+"(DMs only) "
       Endif
       If MessageBaseRecord.BaseType And Sysop.Base Then
          Strng=Strng+"(Sysops only) "
       Endif
       If MessageBaseRecord.BaseType And TownMayor.Base Then
          Strng=Strng+"(Town Mayor) "
       Endif
       If MessageBaseRecord.BaseType And Governor.Base Then
          Strng=Strng+"(Governor) "
       Endif
       If MessageBaseRecord.BaseType And GuildMaster.Base Then
          Strng=Strng+"(Guild Master) "
       Endif
       If MessageBaseRecord.BaseType And 128 Then
          Strng=Strng+"(Assistant DM) "
       Endif
       Strng=Rtrim$(Strng)
       Call IO.O
       If Break Then
          Exit For
       Endif
       Temp1=Temp1+1
       If Temp1>=User.Pagelength-2 Then
          Temp1=False
          If Continuous=False Then
             Call More.Prompt
             If No Or Quit Then
                Exit For
             Endif
          Endif
       Endif
    Endif
 Next
 Allow.Break=False
 Break=False
 Graphics.Off=False
 Strng="Enter message base number(1-"+ _
 Form$(Cdbl(Lof(MessBaseFile)/MessBaseRecLen+2!))+")? "
 Call IO.I
 Temp!=Int(Val(Out2))
 If Temp!<=SFalse Or Temp!>Lof(MessBaseFile)/MessBaseRecLen+2! Then
    Strng=Range$
    Call IO.O
    Var=False
    Exit Sub
 Endif
 Select Case Temp!
 Case 1!
    Message.Name="public"
    Message.Base.Name=Public.Filename
    Message.Base.Number=1!
    Var=True
 Case 2!
    Message.Name="private"
    Message.Base.Name=Private.Filename
    Message.Base.Number=2!
    Var=True
 Case Else
    Call Read.Record(MessBaseFile,Temp!-2!)
    Out2=MessageBaseRecord.BaseMessName
    Out2=Rtrim$(Out2)
    Out2=Lcase$(Out2)
    If Out2=Nul Then
       Out2="<none>"
    Endif
    If MessageBaseRecord.BaseDeleted Then
       Strng="Deleted message base."
       Call IO.O
       Var=False
       Exit Sub
    Endif
    Temp2=False
    If MessageBaseRecord.BaseType And Public.Base Then
       Temp2=True
    Endif
    If MessageBaseRecord.BaseType And Private.Base Then
       Temp2=True
    Endif
    If MessageBaseRecord.BaseType And DM.Base Then
       If Dungeon.Master Or Sysop Then
          Temp2=True
       Endif
    Endif
    If MessageBaseRecord.BaseType And Sysop.Base Then
       If Sysop Then
          Temp2=True
       Endif
    Endif
    If MessageBaseRecord.BaseType And TownMayor.Base Then
       If UserRecord.Flags And Special.Char1 Then
          Temp2=True
       Endif
    Endif
    If MessageBaseRecord.BaseType And Governor.Base Then
       If UserRecord.Flags And Special.Char2 Then
          Temp2=True
       Endif
    Endif
    If MessageBaseRecord.BaseType And GuildMaster.Base Then
       If UserRecord.Flags And Special.Char3 Then
          Temp2=True
       Endif
    Endif
    If MessageBaseRecord.BaseType And 128 Then
       If Dungeon.Master.Assistant Or Sysop Then
          Temp2=True
       Endif
    Endif
    If VarQ Then
       Temp2=True
    Endif
    If Temp2 Then
       Message.Name=MessageBaseRecord.BaseMessName
       Message.Base.Name=MessageBaseRecord.BaseFileName
       Message.Base.Number=Temp!
       Var=True
    Else
       Strng="You can not select message base #"+Form$(Cdbl(Temp!))+"."
       Call IO.O
       Var=False
    Endif
 End Select
Error.Resume43:
 Exit Sub
Error.Trap43:
 Resume Error.Resume43
End Sub

Sub Store.Message
 On Local Error Goto Error.Trap45
 If Message.Length=False Then
    Strng="No message text to store.."
    Call IO.O
    Exit Sub
 Endif
 Strng="Storing message.."
 Call IO.O
Start.StoreX:
 If Share.Installed Then
    Lock #MessageFile
 Endif
 Strng=UserRecord.CodeName
 Strng=Rtrim$(Strng)
 Strng=Ucase$(Strng)
 Strng2=Message.To
 Strng2=Rtrim$(Strng2)
 Strng2=Ucase$(Strng2)
 If Strng=Strng2 Then
    Message.To=Nul
 Endif
 VarZ!=Lof(MessageFile)/MessageRecLen+1!
 VarQ!=Lof(TableFile)/TableRecLen+1!
 If Message.Reply Then
    TableRecord.Thread=Message.Thread
 Else
    TableRecord.Thread=SFalse
 Endif
 TableRecord.ClassType=UserRecord.ClassType
 TableRecord.Clock=Fclock2$
 TableRecord.Date=DateS$
 TableRecord.Flags=UserRecord.Flags
 TableRecord.From=Strng
 TableRecord.Killed=False
 TableRecord.Length=Message.Length
 TableRecord.Private=Private.Message
 TableRecord.Received=False
 TableRecord.Reply=Message.Reply
 TableRecord.Start=VarZ!
 TableRecord.Subject=Subject
 TableRecord.Time=Format$(Now,"hh:mm:ss")
 TableRecord.Timer=Timeit!
 TableRecord.TimesRead=DFalse
 TableRecord.To=Message.To
 Call Write.Record(TableFile,VarQ!)
 For VarX=1 To Message.Length
    Strng=Temp.ArrayS(VarX)
    Strng=Left$(Strng,80)
    Call Valid(Strng,80)
    Call Crypto(Strng)
    BufferRecord.Buffer=Strng
    Put MessageFile,VarZ!,BufferRecord
    VarZ!=VarZ!+1!
 Next
 If Share.Installed Then
    Unlock #MessageFile
 Endif
 Strng="Lines stored:"+Str$(Message.Length)+"."
 Call IO.O
Error.Resume45:
 Exit Sub
Error.Trap45:
 Data.Error=Err
 If Share.Installed Then
    If Data.Error=70 Then
       Resume Start.StoreX
    Endif
 Endif
 Strng="Data error"+Str$(Err)
 Call IO.O
 Resume Error.Resume45
End Sub

Sub Open.Mail
 On Local Error Goto Error.Trap46
 Close #TableFile, #MessageFile
 Message.Base.Name=Rtrim$(Message.Base.Name)
 FileName=Data.Path4+Message.Base.Name+".TBL"
 Open FileName For Random Shared As #TableFile Len=TableRecLen
 FileName=Data.Path4+Message.Base.Name+".DAT"
 Open FileName For Random Shared As #MessageFile Len=MessageRecLen
Error.Resume46:
 Exit Sub
Error.Trap46:
 Resume Error.Resume46
End Sub

Sub Message.Header(Var3!)
 On Local Error Goto Error.Trap55
 VarZ!=Var3!
 Call Sub.Header(VarZ!)
 Strng="Rcvd:  "
 If TableRecord.Received Then
    Strng=Strng+"Yes"
 Else
    Strng=Strng+"No"
 Endif
 Strng=Strng+Space$(35-Len(Strng))
 Var#=TableRecord.TimesRead
 Select Case Var#
 Case 1#
    Strng=Strng+"Read: once"
 Case Else
    Strng=Strng+"Read: "+Form$(Var#)+" times"
 End Select
 Call IO.O
 Strng="Reply: "
 If TableRecord.Reply Then
    Strng=Strng+"Yes"
 Else
    Strng=Strng+"No"
 Endif
 Strng=Strng+Space$(35-Len(Strng))
 Strng=Strng+"Thread: "
 If TableRecord.Reply Then
    Var!=TableRecord.Thread
    If Var!>SFalse Then
       Strng=Strng+Form$(Cdbl(TableRecord.Thread))
    Else
       Strng=Strng+"(forward)"
    Endif
 Else
    Strng=Strng+"None"
 Endif
 Call IO.O
 Strng="Stat:  "
 Class.Number=TableRecord.ClassType
 Select Case Class.Number
 Case 1 To 10
    Strng=Strng+Rtrim$(Class.Name(Class.Number))
 End Select
 Strng=Left$(Strng,35)
 Strng=Strng+Space$(35-Len(Strng))
 Strng=Strng+"Type: "
 Strng2=Nul
 If TableRecord.Flags And Special.Char1 Then
    Strng2=Strng2+"Mayor, "
 Endif
 If TableRecord.Flags And Special.Char2 Then
    Strng2=Strng2+"Governor, "
 Endif
 If TableRecord.Flags And Special.Char3 Then
    Strng2=Strng2+"Guild Master, "
 Endif
 If TableRecord.Flags And Special.Char4 Then
    Strng2=Strng2+"Sysop, "
 Endif
 If Right$(Strng2, 2) = ", " Then
    Strng2 = Left$(Strng2, Len(Strng2) - 2)
 Endif
 If Strng2=Nul Then
    Strng2="None"
 Endif
 Strng=Strng+Strng2
 Strng=Left$(Strng,79)
 Strng=Rtrim$(Strng)
 Call IO.O
Error.Resume55:
 Exit Sub
Error.Trap55:
 Resume Error.Resume55
End Sub

Sub Sub.Header(Var1!)
 On Local Error Goto Error.Trap56
 Graphics.Off=False
 Strng="Msg#: "+Form$(Cdbl(Var1!))+" of "+ _
 Form$(Cdbl(Lof(TableFile)/TableRecLen))
 If TableRecord.Private Then
    Strng=Strng+" (private)"
 Endif
 If TableRecord.Killed Then
    Strng=Strng+" (deleted)"
 Endif
 Call IO.O
 Graphics.Off=True
 Strng2=TableRecord.From
 Strng2=Lcase$(Strng2)
 Mid$(Strng2,1,1)=Ucase$(Mid$(Strng2,1,1))
 Strng="From:  "+Strng2
 Strng=Left$(Strng,35)
 Strng=Strng+Space$(35-Len(Strng))
 Strng2=Rtrim$(TableRecord.Subject)
 Mid$(Strng2,1,1)=Ucase$(Mid$(Strng2,1,1))
 Strng=Strng+"Subj: "+Strng2
 Call IO.O
 Strng2=TableRecord.To
 Strng2=Rtrim$(Strng2)
 If Strng2=Nul Then
    Strng2="ALL"
 Endif
 Strng2=Lcase$(Strng2)
 Mid$(Strng2,1,1)=Ucase$(Mid$(Strng2,1,1))
 Strng="To:    "+Strng2
 Strng=Left$(Strng,35)
 Strng=Strng+Space$(35-Len(Strng))
 Strng=Strng+"Time: "+TableRecord.Clock
 Call IO.O
Error.Resume56:
 Exit Sub
Error.Trap56:
 Resume Error.Resume56
End Sub

Sub Mail.Status.Line
 On Local Error Goto Error.Trap35
 Temp$=UserRecord.CodeName
 Temp$=Rtrim$(Temp$)
 Temp$=Lcase$(Temp$)
 Mid$(Temp$,1,1)=Ucase$(Mid$(Temp$,1,1))
 Temp$=Temp$+" <timeon: "+Fclock$+"> "
 If UserRecord.Flags And Locked.User Then
    Temp$=Temp$+"Mailbox locked"
 Else
    Temp$=Temp$+"Mailbox unlocked"
 Endif
 Temp$=Left$(Temp$,79)
 Temp$=Temp$+Space$(79-Len(Temp$))
 Call Display.Status.Line(True)
Error.Resume35:
 Exit Sub
Error.Trap35:
 Resume Error.Resume35
End Sub

Sub PrivateMessage
 On Local Error Goto Error.Trap36x
 Var2=False
 If Message.Base.Number=2! Then
    Var2=True
 Else
    If Message.Base.Number>2! Then
       If MessageBaseRecord.BaseType And Private.Base Then
          Var2=True
       Endif
    Endif
 Endif
 If Var2 Then
    Do While Lost.Carrier=False
       Strng="Private message(y/n)? "
       Line.Length=1
       No.Input.Out="N"
       Call IO.I
       If Ucase$(Out2)="Y" Then
          Private.Message=-1
          Exit Do
       Endif
       If Ucase$(Out2)="N" Then
          Private.Message=0
          Exit Do
       Endif
    Loop
 Endif
Error.Resume36x:
 Exit Sub
Error.Trap36x:
 Resume Error.Resume36x
End Sub

Sub Clear.Status.Line
 On Local Error Goto Error.Trap58a
 Temp$=Space$(79)
 Call Display.Status.Line(False)
Error.Resume58a:
 Exit Sub
Error.Trap58a:
 Resume Error.Resume58a
End Sub

Sub Alt.Login(Var,Var$)
 On Local Error Goto ErrorTrp25
 If Instr(Var$,"/N:") Then
    Var$=Left$(Var$,Instr(Var$,"/N:")-1)
 Endif
 Out2=Nul
 Var=False
 If Len(Var$) Then
    Var2=Instr(Var$,Chr$(34))
    If Var2 Then
       Var$=Mid$(Var$,Var2+1)
       Var2=Instr(Var$,Chr$(34))
       If Var2 Then
          Out2=Left$(Var$,Var2-1)
          If Out2=Nul Then
             Exit Sub
          Endif
       Else
          Exit Sub
       Endif
    Else
       Exit Sub
    Endif
 Endif
Start.Login:
 If Out2=Nul Then
    Graphics.Off=False
    Strng="Enter codename(?=list,*=search): "
    Call IO.I
 Endif
 Strng=Lcase$(Rtrim$(Out2))
 Out2=Nul
 If Len(Strng)=0 Then
    Exit Sub
 Endif
 If Strng="?" Then
    Temp1=False
    For Temp1!=1! To Lof(UserFile)/UserRecLen
       Call Read.Record(UserFile,Temp1!)
       Out3=UserRecord.CodeName
       Out3=Lcase$(Rtrim$(Out3))
       If Out3<>"<deleted>" Then
          Strng=Out3
          Mid$(Strng,1,1)=Ucase$(Mid$(Strng,1,1))
          Strng=Rtrim$(UserRecord.Prefix1)+Strng
          Call Convert.ANSI(True,VarQ,VarR)
          Carriage.Return=True
          Graphics.On=True
          Call IO.O
          Graphics.On=False
          Strng=Strng+" (level "+Form$(Cdbl(UserRecord.Level))+")"
          If UserRecord.ClassType=AsstDM Then
             Strng=Strng+" [AsstDM]"
          Endif
          If UserRecord.ClassType=DM Then
             Strng=Strng+" [DM]"
          Endif
          If UserRecord.Flags And Special.Char4 Then
             Strng=Strng+" [Sysop]"
          Endif
          Call Search.Mess.File(Temp1!,Var1)
          If Var1 Then
             Strng=Strng+" {online}"
          Endif
          Call IO.O
          Temp1=Temp1+1
          If Temp1>=User.Pagelength-2 Then
             Temp1=False
             Call More.Prompt
             If No Or Quit Then
                Exit For
             Endif
          Endif
       Endif
    Next
    If Temp1 Then
       Call More.Prompt
    Endif
    Out2=Nul
    Goto Start.Login
 Endif
 If Strng="*" Then
    Strng="Enter codename search(?,* allowed): "
    Call IO.I
    Var2$=Lcase$(Out2)
    Temp1=False
    Var2=False
    For Temp1!=1! To Lof(UserFile)/UserRecLen
       Call Read.Record(UserFile,Temp1!)
       Out3=UserRecord.CodeName
       Out3=Lcase$(Rtrim$(Out3))
       If Out3<>"<deleted>" Then
          Out2=Var2$
          Call InstrSUB2(VarX)
          If VarX Then
             Var2=True
             Strng=Out3
             Mid$(Strng,1,1)=Ucase$(Mid$(Strng,1,1))
             Strng=Rtrim$(UserRecord.Prefix1)+Strng
             Call Convert.ANSI(True,VarQ,VarR)
             Carriage.Return=True
             Graphics.On=True
             Call IO.O
             Graphics.On=False
             Strng=Strng+" (level "+Form$(Cdbl(UserRecord.Level))+")"
             If UserRecord.ClassType=AsstDM Then
                Strng=Strng+" [AsstDM]"
             Endif
             If UserRecord.ClassType=DM Then
                Strng=Strng+" [DM]"
             Endif
             If UserRecord.Flags And Special.Char4 Then
                Strng=Strng+" [Sysop]"
             Endif
             Call Search.Mess.File(Temp1!,Var1)
             If Var1 Then
                Strng=Strng+" {online}"
             Endif
             Call IO.O
             Temp1=Temp1+1
             If Temp1>=User.Pagelength-2 Then
                Temp1=False
                Call More.Prompt
                If No Or Quit Then
                   Exit For
                Endif
             Endif
          Endif
       Endif
    Next
    If Var2=False Then
       Strng="Codename not found."
       Call IO.O
    Endif
    If Temp1 Then
       Call More.Prompt
    Endif
    Out2=Nul
    Goto Start.Login
 Endif
 For User.Index=1! To Lof(UserFile)/UserRecLen
    Call Read.Record(UserFile,User.Index)
    Out3=UserRecord.CodeName
    Out3=Lcase$(Rtrim$(Out3))
    If Strng=Out3 Then
       Var=True ' valid name
       Exit Sub
    Endif
 Next
 User.Index=SFalse
 Exit Sub
ErrorRsm25:
 Exit Sub
ErrorTrp25:
 Security.Guard=False
 Resume ErrorRsm25
End Sub

Sub Get.Node
 On Local Error Goto Node.Error
 Var$=Command$
 Var$=Ltrim$(Rtrim$(Var$))
 If Instr(Var$,"/N:") Then
    Var$=Mid$(Var$,Instr(Var$,"/N:")+3)
    Select Case Len(Var$)
    Case 0
       Node=0
       NodeX=Nul
       Exit Sub
    Case 1 ' 0-9,A-Z
       Select Case Var$
       Case "0" To "9"
          Node=Val(Var$)+1
          NodeX=Var$
       Case "A" To "Z"
          Node=Asc(Var$)-54
          NodeX=Var$
       Case Else
          Goto Node.Error
       End Select
    Case 2 ' 10-99
       VarX=Int(Val(Var$))
       If VarX>=10 And VarX<=99 Then
          Node=VarX+27 ' 37-126
          NodeX=Mid$(Str$(VarX),2) ' 10-99
       Else
          Goto Node.Error
       Endif
    Case Else
       Goto Node.Error
    End Select
 Endif
 Exit Sub
Node.Error:
 Color 14,0
 Out2="CMD086 Module - Mail"+Chr$(13)+Chr$(10)
 Out3="Error reading node. Node must be <nul>,0-9,A-Z,10-99."
 Call Terminate.Program
End Sub

Sub Valid.Node
 On Local Error Goto ErrorTrap11
 If Node>=False And Node<=MaxNodes Then
    VarX2=Node+1
    Call Read.Message.Record(MessWorkFile1,VarX2)
    If MessWorkRecord1.ActiveNode Then
       If Rtrim$(NodeX)=Nul Then
          Strng="Node -, already active."
       Else
          Strng="Node "+NodeX+", already active."
       Endif
       Goto ErrorTrap11
    Else
       Strng=Rtrim$(MessWorkRecord1.UserName)
       Call Valid.Name(Strng)
       If TempA Then
          If Rtrim$(NodeX)=Nul Then
             Strng="Node -, active codename."
          Else
             Strng="Node "+NodeX+", active codename."
          Endif
          Goto ErrorTrap11
       Endif
    Endif
 Else
    Strng="Node '"+NodeX+"' is not a valid node number."
    Goto ErrorTrap11
 Endif
ErrorResume11:
 Exit Sub
ErrorTrap11:
 Color 14,0
 Out2="CMD086 Module - Mail"+Chr$(13)+Chr$(10)
 Out3=Strng
 Call Terminate.Program
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
 Out2="CMD086 Module - Mail"+Chr$(13)+Chr$(10)
 Out3="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"+NodeX+".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 38
       Logoff.Help.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:
 Color 14,0
 Out2="CMD086 Module - Mail"+Chr$(13)+Chr$(10)
 Out3="Error reading "+Lcase$(FileName)+" (error:"+Str$(Err)+"). 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
 Out2="Error increasing file handles."+Chr$(13)+Chr$(10)
 Out3="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
 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
 Help.FileName1=Data.Path1+Help.Filename1+File.Extension1
 Help.FileName2=Data.Path1+Help.Filename2+File.Extension1
 Logoff.Help.FileName=Data.Path1+Logoff.Help.FileName+File.Extension1
 Exit Sub
Make.Error:
 Color 14,0
 Out2="CMD086 Module - Mail"+Chr$(13)+Chr$(10)
 Out3="Error making "+Lcase$(FileName)+" (error:"+Str$(Err)+"). Increase files= in config.sys or run Dndcnfg."+Chr$(13)+Chr$(10)
 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:
 Color 14,0
 Out2="CMD086 Module - Mail"+Chr$(13)+Chr$(10)
 Out3="Error opening "+Lcase$(FileName)+" (error:"+Str$(Err)+"). Increase files= in config.sys or run Dndcnfg."+Chr$(13)+Chr$(10)
 Call Terminate.Program
End Sub

Sub Read.Options
 On Local Error Goto Error.Trap13
 Redim Options.Array(1 To 165) As String
 Options.Lines=165
 Var=0
 Close #TempFile1
 Filename=DND.Path+"option"+nodex+".cfg"
 If Dir$(Filename)<>Nul Then
    Open Filename For Input As #TempFile1
    Do
       If Eof(TempFile1) Then
          Exit Do
       Endif
       Line Input #TempFile1, Var$
       Var$=Rtrim$(Var$)
       If Left$(Var$,1)=";" Then
          Eat$ = Nul
       Else
          If Len(Var$) Then
             Var=Var+1
             If Var>Options.Lines Then
                Options.Lines=Options.Lines+10
                Redim Preserve Options.Array(1 To Options.Lines) As String
             Endif
             Options.Array(Var)=Var$
          Endif
       Endif
    Loop
 Endif
 Options.Lines=Var
Error.Resume13:
 Exit Sub
Error.Trap13:
 Color 14,0
 Out2="CMD086 Module - Mail"+Chr$(13)+Chr$(10)
 Out3="Error"+Str$(Err)+" reading "+FileName+". Edit file and restart."
 Call Terminate.Program
 Resume Error.Resume13
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 Detect.Share
 On Local Error Goto ErrResume149b
 Call Plex.Function(16)
 If (OutregsX.AX And &HFF)=&HFF Then
    Share.Installed=True
 Else
    Share.Installed=False
 Endif
 Windows.Detected = False
 Call Plex.Function(22)
 If OutregsX.BX>0 Then
    Windows.Detected = True
    ' store windows version
    Win.Minor=OutregsX.BX And &HFF
    Win.Major=(OutregsX.BX And &HFF00)/256
 Endif
ErrExit149b:
 Exit Sub
ErrResume149b:
 Resume ErrExit149b
End Sub

Sub Read.Rows(Var)
 On Local Error Goto Error.Trap62x
 Temp1=50
 Locate 50,1,0
 Var=50
 Exit Sub
Next.Trap1:
 Temp1=43
 Locate 43,1,0
 Var=43
 Exit Sub
Next.Trap2:
 Temp1=25
 Locate 25,1,0
 Var=25
 Exit Sub
Next.Trap3:
 Var=12
Error.Resume62x:
 Exit Sub
Error.Trap62x:
 If Temp1=50 Then
    Resume Next.Trap1
 Endif
 If Temp1=43 Then
    Resume Next.Trap2
 Endif
 If Temp1=25 Then
    Resume Next.Trap3
 Endif
 Resume Error.Resume62x
End Sub

Sub Search.Mess.File(Var1!,Var2)
 On Local Error Goto ErrMain41
 Var2=False
 For TempA=False To MaxNodes
    Call Read.Message.Record(MessWorkFile1,TempA+1)
    Var$=MessWorkRecord1.UserName
    Select Case Rtrim$(Lcase$(Var$))
    Case "login", "logoff", "relogin"
       TempB=False
    Case Deleted$, Offline$
       TempB=False
    Case Else
       TempB=True
    End Select
    If TempB Then
       If MessWorkRecord1.UserIndex=Var1! Then
          Var2=True
          Exit For
       Endif
    Endif
 Next
MainExit41:
 Exit Sub
ErrMain41:
 Resume MainExit41
End Sub

Sub Back.Space2(Var)
 On Local Error Goto Error.Trap27z
 If Local.Mode=False Then
    If Remote.ANSI.Color Or Remote.Avatar.Color Then
       For Var2=1 To Var
          Var$=Chr$(27)+"[D"
          Call Put.Modem(Var$)
       Next
    Else
       For Var2=1 To Var
          Var$=Chr$(8)
          Call Put.Modem(Var$)
       Next
    Endif
 Endif
 If Local.ANSI.Color Or Local.Avatar.Color Then
    For Var2=1 To Var
       Var$=Chr$(27)+"[D"
       Call Put.Screen(Var$)
    Next
 Else
    For Var2=1 To Var
       Locate Csrlin,Pos(0)-1,1
    Next
 Endif
Error.Resume27z:
 Exit Sub
Error.Trap27z:
 Resume Error.Resume27z
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$
   P3 = S3 ' position match
   DO
      ' check match
      IF P2 > LEN(S2$) THEN
         Var = P3
         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
            P3 = P1
            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

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
