home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / QM95REAL.ZIP / SCRIPTS.Z / HOST.QSC < prev    next >
Text File  |  1995-08-24  |  19KB  |  743 lines

  1. '
  2. ' Host mode script for QmodemPro for Windows.
  3. '
  4. ' Version 2.00
  5. '
  6. ' Last updated August 5, 1995.
  7. '
  8.  
  9. '$include 'hostutil.qsc'
  10.  
  11. ' Constants
  12.  
  13. const BS  = chr(8)
  14. const LF  = chr(10)
  15. const CR  = chr(13)
  16. const ESC = chr(27)
  17.  
  18. const PrelogFileNamePart   = "host.pre"
  19. const MenuFileNamePart     = "host.mnu"
  20. const ProtocolFileNamePart = "host.pro"
  21. const LogoffFileNamePart   = "host.off"
  22. const HelpFileNamePart     = "host.hlp"
  23.  
  24. const UserFileNamePart      = "host.usr"
  25. const MsgHeaderFileNamePart = "host.hdr"
  26. const MsgDetailFileNamePart = "host.msg"
  27.  
  28. const MaxMsgLines = 99
  29.  
  30. ' Type declarations
  31.  
  32. dialog SetupDialog 18, 18, 214, 240
  33.   caption "QmodemPro Host Setup"
  34.   groupbox "Mode", 101, 18, 9, 74, 64
  35.   modeopen as radiobutton "Open", 102, 26, 23, 62, 12
  36.   modeclosed as radiobutton "Closed", 103, 26, 38, 62, 12
  37.   modecallback as radiobutton "Callback", 104, 26, 53, 62, 12
  38.   groupbox "Security", 150, 100, 9, 100, 64
  39.   maxtime as edittext 105, 151, 22, 42, 12
  40.   dospass as edittext 106, 151, 39, 42, 12
  41.   shutdownpass as edittext 107, 151, 56, 42, 12
  42.   rtext "Max time", -1, 108, 25, 41, 8
  43.   rtext "DOS pwd", -1, 108, 41, 41, 8
  44.   rtext "Shutdown pwd", -1, 108, 59, 41, 8
  45.   groupbox "File transfers", 160, 18, 80, 182, 85
  46.   dlpath as edittext 108, 22, 104, 169, 12
  47.   ulpath as edittext 109, 22, 130, 169, 12
  48.   ltext "Download path", -1, 24, 95, 62, 8
  49.   ltext "Upload path", -1, 24, 120, 69, 8
  50.   sysopanypath as checkbox "Sysop can download from any path", 110, 25, 148, 165, 12
  51.   groupbox "Modem", 170, 18, 175, 182, 30
  52.   modem as combobox 111, 25, 187, 165, 80
  53.   pushbutton "&Modem...", 200, 15, 215, 50, 14
  54.   defpushbutton "OK", IDOK, 81, 215, 50, 14
  55.   pushbutton "Cancel", IDCANCEL, 150, 215, 50, 14
  56. end dialog
  57.  
  58. dialog ModemSetupDialog 6, 15, 194, 179
  59.   caption "QmodemPro Host Modem Setup"
  60.   groupbox "", -1, 8, 9, 177, 139
  61.   init as edittext 101, 48, 17, 127, 12
  62.   answer as edittext 102, 48, 33, 47, 12
  63.   busy as edittext 103, 48, 49, 47, 12
  64.   ok as edittext 104, 48, 65, 47, 12
  65.   ring as edittext 105, 129, 33, 45, 12
  66.   ringcount as edittext 106, 148, 49, 27, 12
  67.   rtext "&Init", -1, 16, 19, 28, 8
  68.   rtext "&Answer", -1, 12, 34, 33, 8
  69.   rtext "&Busy", -1, 12, 50, 33, 8
  70.   rtext "&OK msg", -1, 13, 66, 32, 8
  71.   rtext "&Ring", -1, 105, 35, 20, 8
  72.   rtext "Ring &Count", -1, 106, 51, 38, 8
  73.   defpushbutton "OK", IDOK, 77, 156, 50, 14
  74.   pushbutton "Cancel", IDCANCEL, 137, 156, 50, 14
  75. end dialog
  76.  
  77. type TUser
  78.   Name as string*25
  79.   Password as string*20
  80.   Level as integer
  81.   Phone as string*30
  82. end type
  83.  
  84. type TMessageHeader
  85.   Sender as string*25
  86.   Receiver as string*25
  87.   Subject as string*75
  88.   DateTime as string*20
  89.   Private as integer
  90.   Received as integer
  91.   Killed as integer
  92.   Lines as integer
  93.   Detailpos as long
  94. end type
  95.  
  96. ' connection variables
  97. dim Local as integer
  98. dim Port as integer
  99. dim ModemResult as string
  100. dim BaudRate as long
  101. dim LogonTime as DateTime
  102. dim LogoffTime as DateTime
  103. dim ForceLogoff as integer
  104.  
  105. dim Setup as SetupDialog
  106. dim ModemSetup as ModemSetupDialog
  107. dim User as TUser
  108. dim MsgLines(MaxMsgLines) as string
  109.  
  110. dim PrelogFileName as string
  111. dim MenuFileName as string
  112. dim ProtocolFileName as string
  113. dim LogoffFileName as string
  114. dim HelpFileName as string
  115. dim UserFileName as string
  116. dim MsgHeaderFileName as string
  117. dim MsgDetailFileName as string
  118.  
  119. '$include 'hostcfg.qsc'
  120.  
  121. declare sub PackMessages
  122.  
  123. ' Utility routines
  124.  
  125. function MinutesSince(dt as DateTime)
  126.   dim now as DateTime
  127.   GetCurrentDateTime(now)
  128.   dim days as integer, seconds as integer
  129.   DateTimeDiff(now, dt, days, seconds)
  130.   MinutesSince = (days * 86400 + seconds) / 60
  131. end function
  132.  
  133. function MinutesUntil(dt as DateTime)
  134.   dim now as DateTime
  135.   GetCurrentDateTime(now)
  136.   dim days as integer, seconds as integer
  137.   DateTimeDiff(now, dt, days, seconds)  
  138.   MinutesUntil = (days * 86400 + seconds) / 60
  139. end function
  140.  
  141. function TimeLeft as integer
  142.   TimeLeft = MinutesUntil(LogoffTime)
  143. end function
  144.  
  145. function CallerHungUp as integer
  146.   CallerHungUp = (not Local and not Carrier) or ForceLogoff
  147. end function
  148.  
  149. sub DoChat
  150.   dim s as string, c as string
  151.   send #Port,
  152.   send #Port, "You are now chatting with the sysop"
  153.   send #Port,
  154.   do
  155.     c = inkey
  156.     if c = "F2" then
  157.       exit do
  158.     end if
  159.     if c = "" and not Local then
  160.       c = inkey(Port)
  161.     end if
  162.     select case c
  163.       case BS
  164.         if len(s) > 0 then
  165.           s = left(s, len(s)-1)
  166.           send #Port, BS; " "; BS;
  167.         end if
  168.       case CR
  169.         send #Port,
  170.         s = ""
  171.       case is >= " "
  172.         if len(c) = 1 then
  173.           s = s + c
  174.           send #Port, c;
  175.           if len(s) >= 79 then
  176.             if instr(s, " ") then
  177.               dim i as integer
  178.               i = len(s)
  179.               while mid(s, i, 1) <> " "
  180.                 i = i - 1
  181.               wend
  182.               send #Port, string(len(s)-i, BS); string(len(s)-i, " ")
  183.               s = mid(s, i+1, len(s)-i)
  184.               send #Port, s;
  185.             else
  186.               send #Port,
  187.               s = ""
  188.             end if
  189.           end if
  190.         end if
  191.     end select
  192.   loop until CallerHungUp
  193.   send #Port,
  194.   send #Port,
  195.   send #Port, "Returning you to host mode"
  196.   send #Port,
  197. end sub
  198.  
  199. function YesNo(x as integer) as string
  200.   if x then
  201.     YesNo = "Yes"
  202.   else
  203.     YesNo = "No"
  204.   end if
  205. end function
  206.  
  207. declare function GetLine(prompt as string = "", maxlen as integer = 0, start as string = "", passchar as string = "") as string
  208. function GetLine(prompt as string, maxlen as integer, start as string, passchar as string) as string
  209.   dim s as string
  210.   dim starttime as DateTime
  211.   dim warned as integer
  212.   GetCurrentDateTime(starttime)
  213.   warned = false
  214.   s = start
  215.   send #Port, prompt; s;
  216.   do
  217.     dim c as string
  218.     c = inkey
  219.     if c = "" and not Local then
  220.       c = inkey(Port)
  221.     end if
  222.     select case c
  223.       case ""
  224.         dim idle as integer
  225.         idle = MinutesSince(starttime)
  226.         if idle >= 4 and not warned then
  227.           send #Port,
  228.           send #Port,
  229.           send #Port, "CAUTION!  You will be logged off if you do not continue in 60 seconds!"
  230.           send #Port,
  231.           send #Port, prompt; s;
  232.           warned = true
  233.         elseif idle >= 5 then
  234.           send #Port,
  235.           send #Port,
  236.           send #Port, "Logged off due to inactivity."
  237.           delay 1
  238.           hangup
  239.           ForceLogoff = True
  240.         end if
  241.       case "F2"
  242.         DoChat
  243.         GetCurrentDateTime(starttime)
  244.         send #Port, prompt; s;
  245.       case BS
  246.         if len(s) > 0 then
  247.           s = left(s, len(s)-1)
  248.           send #Port, BS;" ";BS;
  249.         end if
  250.       case CR
  251.         GetLine = s
  252.         send #Port,
  253.         exit function
  254.       case ESC
  255.         ' esc handling
  256.       case is >= " "
  257.         s = s + c
  258.         if len(passchar) > 0 then
  259.           send #Port, passchar;
  260.         else
  261.           send #Port, c;
  262.         end if
  263.         if maxlen > 0 and len(s) >= maxlen then
  264.           GetLine = s
  265.           exit function
  266.         end if
  267.     end select
  268.   loop until TimeLeft < 0 or CallerHungUp
  269.   GetLine = ""
  270. end function
  271.  
  272. function DisplayFile(fn as string) as integer
  273.   dim f as integer, count as integer
  274.   DisplayFile = TRUE
  275.   f = freefile
  276.   open fn for input as #f
  277.   count = 0
  278.   do while not eof(f)
  279.     dim s as string
  280.     input #f, s
  281.     send #Port, s
  282.     count = count + 1
  283.     if count >= 24 then
  284.       if OemUpper(GetLine("-Pause- [C]ontinue, [S]top? ", 1)) = "S" then
  285.         exit do
  286.       end if
  287.       send #Port,
  288.       count = 0
  289.     end if
  290.   loop
  291.   close #f
  292. catch err_fileopen
  293.   DisplayFile = FALSE
  294. end function
  295.  
  296. sub SendModemString(s as string)
  297.   dim i as integer, c as string
  298.   i = 1
  299.   while i <= len(s)
  300.     c = mid(s, i, 1)
  301.     if c = "^" and i+1 <= len(s) then
  302.       i = i + 1
  303.       c = mid(s, i, 1)
  304.       if c = "~" then
  305.         delay 0.5
  306.         goto nextchar
  307.       else
  308.         c = chr(asc(c) and 0x3f)
  309.       end if
  310.     end if
  311.     send c;
  312. nextchar:
  313.     i = i + 1
  314.   wend
  315. end sub
  316.  
  317. sub InitModem
  318.   hostecho off  
  319.   ClosePort
  320.   if Setup.modem < GetModemCount then
  321.     AutoAnswer(GetModemName(Setup.modem))
  322.   else
  323.     dim s as string
  324.     s = "COM"+chr(asc("1")+Setup.modem-GetModemCount)
  325.     if not OpenSerialPort(s) then
  326.       MsgBox("Warning: Could not open serial port "+s)
  327.       exit sub
  328.     end if
  329.     dim result as string
  330.     if carrier then exit sub
  331.     timeout 5
  332.   tryagain:
  333.     delay 1
  334.     SendModemString ModemSetup.init
  335.     do
  336.       receive result
  337.     loop until result = ModemSetup.ok
  338.   end if
  339. catch err_timeout
  340.   goto tryagain
  341. end sub
  342.  
  343. sub UninitModem
  344.   if Setup.modem < GetModemCount then
  345.     AutoAnswer(FALSE)
  346.   else
  347.     ClosePort
  348.   end if
  349. end sub    
  350.  
  351. function ProcessKeyboard(byval k as string)
  352.   ProcessKeyboard = False
  353.   select case OemUpper(k)
  354.     case "F1"
  355.       if ModemSetup.busy <> "" then
  356.         SendModemString ModemSetup.busy
  357.         delay 1
  358.         flush input
  359.       end if
  360.       Local = True
  361.       Port = 0
  362.       ProcessKeyboard = True
  363.     case "F7"
  364.       PackMessages
  365.     case "F8"
  366.       SetupHost
  367.     case "F9"
  368.       print "Host mode terminated, returning to normal operation."
  369.       UninitModem
  370.       end
  371.   end select
  372. end function
  373.  
  374. function WaitForCall as integer
  375.   WaitForCall = False
  376.   hostecho off
  377.   if carrier then
  378.     Local = False
  379.     Port = comm
  380.     WaitForCall = True
  381.     exit function
  382.   end if
  383.   if Setup.modem < GetModemCount then
  384.     do
  385.       select case WaitForEvent
  386.         case 1
  387.           if ProcessKeyboard(inkey) then
  388.             WaitForCall = True
  389.             exit function
  390.           end if
  391.         case 2
  392.           BaudRate = 19200
  393.           Local = False
  394.           Port = comm
  395.           WaitForCall = True
  396.           exit function          
  397.       end select
  398.     loop
  399.   else
  400.     do
  401.       dim rings as integer
  402.       rings = 0
  403.       dim result as string
  404.       do
  405.         dim c as string
  406.         c = inkey(comm)
  407.         if c = "" then
  408.           c = inkey
  409.           if ProcessKeyboard(c) then
  410.             WaitForCall = True
  411.             exit function
  412.           end if
  413.         elseif c = LF then
  414.           result = ""
  415.         else
  416.           result = result + c
  417.           if len(result) > len(ModemSetup.ring) then
  418.             result = right(result, len(result)-1)
  419.           end if
  420.           if result = ModemSetup.ring then
  421.             rings = rings + 1
  422.           end if
  423.         end if
  424.       loop until rings >= val(ModemSetup.ringcount)
  425.       delay 0.2
  426.       SendModemString ModemSetup.answer
  427.       timeout 60
  428.       do
  429.         receive result
  430.         if left(result, 7) = "CONNECT" then
  431.           ModemResult = result
  432.           BaudRate = val(right(ModemResult, len(ModemResult)-8))
  433.           Local = False
  434.           Port = comm
  435.           WaitForCall = True
  436.           exit function
  437.         end if
  438.       loop until result = "NO CARRIER"
  439.     loop
  440.   end if
  441. catch err_timeout
  442.   WaitForCall = False
  443. end function
  444.  
  445. function NextField(s as string, delim as string) as string
  446.   dim i as integer
  447.   i = instr(s, delim)
  448.   if i > 0 then
  449.     NextField = left(s, i-1)
  450.     s = right(s, len(s)-i)
  451.   else
  452.     NextField = s
  453.     s = ""
  454.   end if
  455. end function
  456.  
  457. function LookupUser(byval uname as string, user as TUser) as integer
  458.   dim f as integer, s as string
  459.   LookupUser = False
  460.   f = freefile
  461.   open UserFileName for input as #f
  462.   do while not eof(f)
  463.     input #f, s
  464.     dim i as integer
  465.     i = instr(s, ";")
  466.     if i > 0 then
  467.       s = rtrim(left(s, i-1))
  468.     end if
  469.     if OemUpper(uname)+"," = left(s, len(uname)+1) then
  470.       user.Name = NextField(s, ",")
  471.       user.Password = NextField(s, ",")
  472.       user.Level = val(NextField(s, ","))
  473.       user.Phone = NextField(s, ",")
  474.       close #f
  475.       LookupUser = True
  476.       exit function
  477.     end if
  478.   loop
  479.   close #f
  480. catch err_fileopen
  481. end function
  482.  
  483. function GetPassword as integer
  484.   GetPassword = True
  485.   if User.Password = "" then
  486.     exit function
  487.   end if
  488.   GetPassword = False
  489.   dim password as string, tries as integer
  490.   do
  491.     password = GetLine("Password? ", 0, "", "*")
  492.     if CallerHungUp then
  493.       exit function
  494.     end if
  495.     if OemUpper(password) = OemUpper(User.Password) then
  496.       send #Port, "Password ok"
  497.       GetPassword = True
  498.       exit function
  499.     end if
  500.     tries = tries + 1
  501.     if tries > 3 then
  502.       send #Port,
  503.       send #Port, "Sorry, access denied"
  504.       send #Port,
  505.       exit function
  506.     else
  507.       send #Port,
  508.       send #Port, "Incorrect password entered"
  509.       send #Port,
  510.     end if
  511.   loop
  512.   GetPassword = True
  513. end function
  514.  
  515. function CallUserBack as integer
  516.   CallUserBack = False
  517.   if User.Phone = "" then
  518.     send #Port, "Your phone number is not on file."
  519.     send #Port, "(click)"
  520.     exit function
  521.   end if
  522.   send #Port, "Hanging up now, type ATA and press Enter after you get a ring."
  523.   delay 1
  524.   hostecho off
  525.   hangup
  526.   delay 10
  527.   if Setup.modem < GetModemCount then
  528.     dial manual User.Phone
  529.     if not carrier then
  530.       error err_timeout
  531.     end if
  532.   else
  533.     send "ATDT"; User.Phone
  534.     timeout 60
  535.     dim result as string
  536.     do
  537.       receive result
  538.       if left(result, 7) = "CONNECT" then
  539.         ModemResult = result
  540.         BaudRate = val(right(ModemResult, len(ModemResult)-8))
  541.         exit do
  542.       end if
  543.     loop
  544.     timeout off
  545.   end if
  546.   hostecho on
  547.   delay 1
  548.   send #Port, "Welcome "; User.Name
  549.   send #Port,
  550.   if GetPassword then
  551.     CallUserBack = True
  552.   end if
  553. catch err_timeout
  554.   send
  555. end function
  556.  
  557. function GetCallerInfo as integer
  558.   dim uname as string
  559.   do
  560.     uname = OemUpper(GetLine("Please enter your full name? "))
  561.     if CallerHungUp then
  562.       GetCallerInfo = False
  563.       exit function
  564.     end if
  565.     if LookupUser(uname, User) then
  566.       if not GetPassword then
  567.         GetCallerInfo = False
  568.         exit function
  569.       end if
  570.       if Setup.modecallback and not Local then
  571.         if not CallUserBack then
  572.           GetCallerInfo = False
  573.           exit function
  574.         end if
  575.       end if
  576.       GetCallerInfo = True
  577.       exit function
  578.     elseif Setup.modeopen then
  579.       User.Name = uname
  580.       send #Port,
  581.       send #Port, "Your name ";chr(34);uname;chr(34);" was not found in the user list."
  582.       if OemUpper(left(GetLine("Is it spelled correctly? "), 1)) = "Y" then
  583.         exit do
  584.       end if
  585.       send #Port,
  586.     else
  587.       send #Port,
  588.       send #Port, "Sorry, you are not registered with this system."
  589.       send #Port, "(click)"
  590.       send #Port,
  591.       GetCallerInfo = False
  592.       exit function
  593.     end if
  594.   loop
  595.   send #Port,
  596.   do
  597.     dim password as string
  598.     User.Password = GetLine("Please select a password? ", 0, "", "*")
  599.     password      = GetLine("Type your password again? ", 0, "", "*")
  600.     if OemUpper(password) = OemUpper(User.Password) then exit do
  601.     send #Port,
  602.     send #Port, "The passwords you typed did not match.  Try again."
  603.     send #Port,
  604.   loop
  605.   User.Level = 0
  606.   open UserFileName for append as #1
  607.   print #1, User.Name;",";User.Password;",";User.Level
  608.   close #1
  609.   send #Port, "Welcome new user!"
  610.   GetCallerInfo = True
  611. catch err_fileopen
  612.   send "Fatal error - could not open user database"
  613.   GetCallerInfo = False
  614. end function
  615.  
  616. '$include 'hostfile.qsc'
  617. '$include 'hostmsg.qsc'
  618. '$include 'hostdos.qsc'
  619.  
  620. sub HelpScreen
  621.   if DisplayFile(HelpFileName) then
  622.     do
  623.       dim s as string
  624.       send #Port,
  625.       send #Port, "Type the letter of the command you would like more help with,"
  626.       s = OemUpper(GetLine("or press Enter to return to the main menu: "))
  627.       if s = "" or CallerHungUp then exit do
  628.       send #Port,
  629.       if not DisplayFile(ConfigScriptPath+"\host" + left(s, 1) + ".hlp") then
  630.         send #Port, "Sorry, no help is available for that item."
  631.       end if
  632.     loop
  633.   else
  634.     send #Port, "Sorry, no help information is available."
  635.   end if
  636. end sub
  637.  
  638. ' Page sysop
  639.  
  640. sub PageSysop
  641.   send #Port, "Paging sysop..."
  642.   print "(Sysop: Press F2 to enter chat mode)"
  643.   play "RINGIN"
  644.   send #Port,
  645.   GetLine "Press Enter to continue? "
  646. end sub
  647.  
  648. sub Shutdown
  649.   if User.Level = 0 or Setup.shutdownpass = "" then
  650.     send #Port, "Sorry, shutdown option not available."
  651.     send #Port,
  652.     exit sub
  653.   end if
  654.   if OemUpper(GetLine("Enter shutdown password: ", 0, "", "*")) <> OemUpper(Setup.shutdownpass) then
  655.     send #Port,
  656.     send #Port, "Wrong password entered."
  657.     send #Port,
  658.     exit sub
  659.   end if
  660.   hangup
  661.   UninitModem
  662.   end
  663. end sub
  664.  
  665. do
  666.   PrelogFileName    = ConfigScriptPath+"\"+PrelogFileNamePart
  667.   MenuFileName      = ConfigScriptPath+"\"+MenuFileNamePart
  668.   ProtocolFileName  = ConfigScriptPath+"\"+ProtocolFileNamePart
  669.   LogoffFileName    = ConfigScriptPath+"\"+LogoffFileNamePart
  670.   HelpFileName      = ConfigScriptPath+"\"+HelpFileNamePart
  671.   UserFileName      = ConfigScriptPath+"\"+UserFileNamePart
  672.   MsgHeaderFileName = ConfigScriptPath+"\"+MsgHeaderFileNamePart
  673.   MsgDetailFileName = ConfigScriptPath+"\"+MsgDetailFileNamePart
  674.   LoadConfig
  675.   InitModem
  676.   do
  677.     cls
  678.     print "QmodemPro for Windows Host Mode"
  679.     print
  680.     print "Press F1 to log on locally"
  681.     print "Press F7 to pack the messages"
  682.     print "Press F8 to set up the host mode"
  683.     print "Press F9 to quit the host mode"
  684.     print
  685.     print "Modem ready for calls..."
  686.   loop until WaitForCall
  687.   timeout off
  688.   ForceLogoff = False
  689.   print "Call connected at "; BaudRate; " baud"
  690.   hostecho on
  691.   delay 1
  692.   send #Port, "Welcome to the Qmodem for Windows host mode!"
  693.   send #Port,
  694.   send #Port, "Modem result: "; ModemResult
  695.   send #Port, "Connected at "; BaudRate; " bps. ";
  696.   send #Port,
  697.   send #Port,
  698.   DisplayFile PrelogFileName
  699.   GetCurrentDateTime(LogonTime)
  700.   call IncDateTime(LogonTime, LogoffTime, 0, val(Setup.MaxTime)*60)
  701.   if GetCallerInfo then
  702.     do
  703.       send #Port,
  704.       DisplayFile MenuFileName
  705.       dim cmd as string
  706.       cmd = GetLine("("+str(TimeLeft)+" min. left) Command? ")
  707.       send #Port,
  708.       select case OemUpper(cmd)
  709.         case "?"
  710.           HelpScreen
  711.         case "D"
  712.           DownloadFile
  713.         case "E"
  714.           EnterMessage
  715.         case "F"
  716.           ListFiles
  717.         case "G"
  718.           DisplayFile LogoffFileName
  719.           send #Port, "Thanks for calling!"
  720.           exit do
  721.         case "P"
  722.           PageSysop
  723.         case "R"
  724.           ReadMessages
  725.         case "S"
  726.           DosShell
  727.         case "U"
  728.           UploadFile
  729.         case "Z"
  730.           Shutdown
  731.         case else
  732.           send #Port, "Unknown command, try again"
  733.       end select
  734.     loop until TimeLeft < 0 or CallerHungUp
  735.   end if
  736.   hostecho off
  737.   if not Local then
  738.     delay 1
  739.     hangup
  740.     delay 1
  741.   end if
  742. loop
  743.