home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / ppdial31.zip / PPPDIAL.CMD < prev    next >
OS/2 REXX Batch file  |  1997-02-06  |  34KB  |  970 lines

  1. /* REXX */
  2. /*
  3.      OS/2 WARP REXX script to redial a PPP provider when busy.
  4.  
  5.       Written by: Don Russell (c) 1995, 1996, 1997
  6.       send email to don_russell@ibm.net
  7.  
  8.       Many changes introduced by Ed Tomlinson in version 2.4
  9.       send email to tomlins@CAM.ORG
  10.  
  11. Change log: (most recent first)
  12.         6 February 1997 Version 3.1
  13.              Minor bug fix, add LOGGING capability [PPPDIAL_LOG]
  14.  
  15.    (other history removed, see documentation if interested)
  16.    8 April 1995: Original
  17. stop
  18. A note about distribution.... This script may be distributed freely provided
  19. I am given credit for it. Please do not alter my name or email address
  20. nor the manner in which they are displayed.
  21.  
  22. If you have comments regarding this script, plese let me know by email. I'll
  23. support it as time, and my ability permit.   ;-)
  24.  
  25. NOTE: I've tested this as well as I can with a single provider. Given the many
  26. providers and configurations, this may not work properly the first time.
  27.  
  28. If you have problems with pppdial, please refer to the pppdial.htm file.
  29.  
  30. Specific things to watch for are the EXACT prompts used when the host
  31. system is asking for a userid and password. The prompts that pppdial expect
  32. are "ogin:" (no quotes) and "ssword:" (no quotes) for userid and password
  33. respectfully.
  34.  
  35. If your system uses someting different, you will need to use the response file
  36. option. (Or modify the script slightly. This is not recommended because you will
  37. have to make the same changes in the next version etc. too.)
  38.  
  39. -----------------------------------------------------------------*/
  40. VersionTag = 'PPPDIAL V3.1'
  41.  
  42. RFile = ''
  43. UsePhoneNumberFile = 0
  44. signal on halt
  45.  
  46. LoginPrompt = 'ogin:'
  47. PasswordPrompt = 'ssword:'
  48.  
  49. LoginId = 'userid'
  50. Password = 'password'
  51.  
  52. call rxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  53. call SysLoadFuncs
  54.  
  55. parse upper source . . MyDrivePathName
  56. etcDrivePath = translate( value( 'etc',,'OS2ENVIRONMENT') )
  57. iniFile = etcDrivePath || '\TCPOS2.INI'
  58.  
  59. /* before we get too carried away, let's see what we're doing... */
  60. /* if the ppp_ functions are registered, I assume we're about to */
  61. /* start a ppp connection... */
  62. /* If neither the ppp_ functions NOR the slip_ functions are registered */
  63. /* then I assume we're installing ... */
  64.  
  65. PPPService = ( RxFuncQuery( 'ppp_com_input' ) = 0 )
  66. SLIPService = ( RxFuncQuery( 'slip_com_input' ) = 0 )
  67. if \(PPPService | SLIPService) then do
  68.    call NotFromDialer
  69.    exit 0
  70. end  /* Do */
  71.  
  72. /* Set some definitions for easier COM strings */
  73. bs = '08'x
  74. cr='0d'x
  75. crlf='0d0a'x
  76.  
  77. if PPPService then
  78.    parse arg interface , port , . , RFile
  79. else
  80.    parse arg interface , RFile               /* different when slip :-( */
  81.  
  82. if RFile <> '' then do
  83.    /* The use of slippm.exe is a bit tricky... extra <CR> cause havoc :-( */
  84.    /* Check to see if there are any in the spec and warn the user. */
  85.    if pos(cr, RFile) <> 0 then do
  86.       call lineout , 'Response file is not coded correctly.'
  87.       call lineout , 'Do not press the enter key when typing the response file name'
  88.       call lineout , 'in the login sequence field in slippm.exe'
  89.       exit 8
  90.    end  /* Do */
  91.  
  92.    RFile = stream( RFile, 'C', 'QUERY EXISTS' )
  93.    if RFile = '' then do
  94.       if substr(Rfile, 2, 1) <> ':' then do
  95.             call lineout , 'Response file must have drive and path information'
  96.             call lineout , 'or the working directory path of the dialer must be set.'
  97.             exit 8
  98.          end  /* Do */
  99.       else  do
  100.             call lineout , 'Response file not found.'
  101.             call lineout , 'Processing ended.'
  102.             exit 8
  103.          end
  104.    end  /* Do */
  105. end  /* Do */
  106.  
  107. /*--------------------------------------------------------------------------*/
  108. /*                   Initialization and Main Script Code                    */
  109. /*--------------------------------------------------------------------------*/
  110.  
  111. remain_buffer = ''
  112.  
  113. UsePhoneNumberFile = 0
  114. UsePhoneNumberList = 0
  115. Disable = 0
  116. ActualCarrier = 0     /* to be determined .... */
  117.  
  118. UpperCase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  119. LowerCase = 'abcdefghijklmnopqrstuvwxyz'
  120.  
  121. /* initialize variables that MAY be set by a response file... */
  122. BeepWanted = 1        /* beep when successful connection */
  123. DialPrefix = ''
  124. HostTimeout = 60
  125. init1 = ''
  126. init2 = ''
  127. LogFile = ''
  128. MaxAttempts = 32767
  129. MinCarrier = 0
  130. ModemEscapeSequence = '+++'
  131. ModemRegS7 = -1   /* if still < 0 later, we get it from the modem */
  132. ModemResetCommand = 'ATH0Z'
  133. pause = 5             /* seconds between dial attempts */
  134. PhoneNumber = 'xxx-xxxx'   /* may be a blank delimited list, or file name */
  135. prefix = 'ATDT'            /* add any other commands required */
  136. UseDialer = 1    /* yes, we're using the IBM "Dial Other..." */
  137. AutoStart = ''
  138. DisableSequence = ''
  139.  
  140. if UseDialer then do
  141.     /* Get userid/password etc. from the dialer */
  142.     ConnectTo = strip( SysIni( iniFile, 'CONNECTION', 'CURRENT_CONNECTION' ), 'T', '00'x )
  143.     if (ConnectTo = '') | (ConnectTo = 'ERROR:') then do
  144.        ConnectTo = strip( SysIni( iniFile, 'CONNECTION', 'LAST_CONNECTION' ), 'T', '00'x )
  145.     end /* Do */
  146.     x = Strip( SysIni( iniFile, ConnectTo, 'INIT' ), 'T', '00'x )
  147.     if x <> 'ERROR:' then init1 = x
  148.     x = Strip( SysIni( iniFile, ConnectTo, 'INIT2' ), 'T', '00'x )
  149.     if x <> 'ERROR:' then init2 = x
  150.     x = Strip( SysIni( iniFile, ConnectTo, 'AUTOSTART'), 'T', '00'x );
  151.     if x <> 'ERROR:' then AutoStart = x
  152.     x = Strip( SysIni( iniFile, ConnectTo, 'PREFIX' ), 'T', '00'x )
  153.     if x <> 'ERROR:' then Prefix = x
  154.     x = Strip( SysIni( iniFile, ConnectTo, 'DIAL_PREFIX' ), 'T', '00'x )
  155.     if x <> 'ERROR:' then DialPrefix = x
  156.     x = Strip( SysIni( iniFile, ConnectTo, 'PHONE_NUMBER' ), 'T', '00'x )
  157.     if x <> 'ERROR:' then PhoneNumber = x
  158.     x = Strip( SysIni( iniFile, ConnectTo, 'LOGIN_ID' ), 'T', '00'x )
  159.     if x <> 'ERROR:' then LoginId = x
  160.     x = Strip( SysIni( iniFile, ConnectTo, 'PWD' ), 'T', '00'x )
  161.     if x <> 'ERROR:' then Password = x
  162.     x = Strip( SysIni( iniFile, ConnectTo, 'DISABLE' ), 'T', '00'x )
  163.     if x <> 'ERROR:' then Disable = ( x = 'TRUE' )
  164.     x = Strip( SysIni( iniFile, ConnectTo, 'DISABLE_SEQUENCE' ), 'T', '00'x )
  165.     if x <> 'ERROR:' then DisableSequence = x
  166.        else do /* that ini key was not found... */
  167.           /* The ini file item changed in Warp 4.0 ... */
  168.           x = Strip( SysIni( iniFile, ConnectTo, 'DISABLE_SEQ' ), 'T', '00'x )
  169.           if x <> 'ERROR:' then DisableSequence = x || ','
  170.         end
  171.  
  172.     if (PPPService & SLIPService) then do
  173.        x = Strip( SysIni( iniFile, ConnectTo, 'SERVICE' ), 'T', '00'x )
  174.        if x <> 'ERROR:' then PPPService = ( x = 'PPP' )
  175.     end
  176.     drop x
  177. end /* Do */
  178.  
  179. if RFile <> '' then do
  180.    if \ProcessRFileCommands() then do
  181.       say 'Processing ended due to response file error.'
  182.       exit 8
  183.    end  /* Do */
  184.  
  185.    if (( RFile.1 <> 'GO') & (RFile.1 <> 'WAIT' )) then do
  186.       call lineout , 'First line of response file must be GO or WAIT.'
  187.       call lineout , 'Processing ended.'
  188.       exit 8
  189.    end /* Do */
  190.  
  191. end
  192. else do
  193.    RFile.0 = 0
  194. end  /* Do */
  195.  
  196. if \datatype( pause, 'W' ) then do
  197.    call lineout , 'invalid time delay specified - 5 sec assumed'
  198.    pause = 5
  199. end  /* Do */
  200.  
  201. pause = max( 2, pause )  /* A minimum delay of 2 seconds is required to guarantee dial tone */
  202.  
  203. /* The "phone number" may be a list of numbers, or a file spec of a list of numbers. */
  204. if words( PhoneNumber ) > 1 then do
  205.    /* Yup, it's a list itself... build a stem of numbers to use */
  206.    /* However, it could be a list of "number/pause" pairs... */
  207.    x = 0
  208.    do i = 1 to words( PhoneNumber )
  209.       x = x + 1
  210.  
  211.       PhoneNo.i = word( PhoneNumber, x )
  212.       if right( PhoneNo.i, 1 ) = ';' then do
  213.          if x >= words( PhoneNumber) then do
  214.              call lineout , 'Do not include semicolon on last number dialed'
  215.              exit 8
  216.          end  /* Do */
  217.          PhoneNo.i = PhoneNo.i word( PhoneNumber, x + 1 )
  218.          x = x + 1
  219.       end /* Do */
  220.    end /* do */
  221.    PhoneNo.0 = i - 1
  222.    UsePhoneNumberList = 1
  223.    end  /* Do */
  224. else do
  225.    PhoneNumberFile = stream( PhoneNumber, 'C', 'QUERY EXISTS' )
  226.    if PhoneNumberFile <> '' then do
  227.       /* The phone numbers are in a file. Build a stem variable and close the file */
  228.       UsePhoneNumberFile = 1
  229.       do i = 1 by 1 while lines( PhoneNumberFile )
  230.          PhoneNo.i = linein( PhoneNumberFile )
  231.       end /* do */
  232.       PhoneNo.0 = i - 1
  233.       call lineout PhoneNumberFile   /* close the file */
  234.    end  /* Do */
  235.    else do /* it's not a list or a (found) file... */
  236.        PhoneNo.0 = 1
  237.        PhoneNo.1 = PhoneNumber
  238.    end /* else */
  239. end
  240.  
  241. /* Flush any stuff left over from previous COM activity */
  242. call flush_receive
  243.  
  244. call ResetModem
  245.  
  246. /* How long will the modem wait for carrier? */
  247. /* We have to wait a bit longer for a response then... */
  248.  
  249. /* This value may have been supplied in the response file... */
  250. if ModemRegS7 < 0 then do
  251.    call lineout , 'Determining modem carrier timeout value...'
  252.    call send 'ATS7?' || cr
  253.    x = GetResult( 2 )
  254.    parse var x ModemRegS7 '0d'x .
  255.    if \datatype( ModemRegS7, 'W') then
  256.       ModemRegS7 = 60
  257. end /* Do */
  258.  
  259. FirstTime = 1
  260. connecting = 0
  261. count = 0
  262. LogFileDetailLine = Date() Time()
  263. DialingStartedAt = Time('S')
  264.  
  265. do forever until count>=MaxAttempts
  266.  
  267.     connected = 0
  268.     hangup = 0
  269.  
  270.     if \connecting then do
  271.  
  272.        if \FirstTime then do
  273.           call lineout , 'Waiting' pause 'seconds before retry' count
  274.           call lineout , '  'VersionTag 'by: don_russell@ibm.net'
  275.           call lineout , '          Copyright 1995, 1996, 1997 Don Russell'
  276.           call sysSleep pause
  277.        end  /* Do */
  278.  
  279.        call flush_receive 'echo'
  280.  
  281.        ActualCarrier = 0
  282.        StartedDialing = 0
  283.        DialCmd = BuildDialCmd( 0 )
  284.  
  285.        parse var DialCmd DialCmd PartialDialPause
  286.        PartialDialing = (PartialDialPause <> '')
  287.        if (\PartialDialing) then
  288.           DialCmd = BuildDialCmd( count )
  289.  
  290.        count = count+1
  291.  
  292.        call charout , 'Dialing...'
  293.        call send DialCmd || cr
  294.  
  295.        StartedDialing = 1
  296.        do i = 1 by 1 while PartialDialPause <> ''
  297.           call GetResult( 2 )      /* Get the OK from the dial command that ended with ; */ 
  298.           call sysSleep PartialDialPause
  299.           DialCmd = BuildDialCmd( i )
  300.           parse var DialCmd DialCmd PartialDialPause
  301.           call send DialCmd || cr
  302.        end  /* Do */
  303.  
  304.     end
  305.  
  306.     FirstTime = 0
  307.  
  308.     do until \abbrev( ResultCode, 'RINGING' ) /* & length(ResultCode)>5 */
  309.        ResultCode = getresult( ModemRegS7 + 10 )
  310.     end /* Do until */
  311.  
  312. /* debugging
  313. say c2x(ResultCode)
  314. say '"'translate(ResultCode, LowerCase, UpperCase)'"'
  315. */
  316.     select
  317.  
  318.        /* Modem responses that indicate we should redial */
  319.        when abbrev( ResultCode, 'BUSY' ) then connecting = 0
  320.        when abbrev( ResultCode, 'NO CARRIER' ) then connecting = 0
  321.        when abbrev( ResultCode, 'NO ANSWER' ) then connecting = 0
  322.        when abbrev( ResultCode, 'NO DIALTONE' ) then connecting = 0
  323.  
  324.        /* Modem responses that indicate we should hangup and redial */
  325.        /* My modem supports an &N command that allows me to set the */
  326.        /* acceptable connect rate. By setting this at the highest setting */
  327.        /* I cause redialing to occur until I get that speed. */
  328.  
  329.        /* modem responses that indicate we got connected */
  330.  
  331.        when abbrev( ResultCode, 'COMPRESSION' ) then connecting = 1   /* TRON, Supra  */
  332.        when abbrev( ResultCode, 'PROTOCOL' ) then connecting = 1      /* Megahertz */
  333.  
  334.        when abbrev( ResultCode, 'CARRIER' ) then do
  335.           if GoodCarrier( ResultCode, MinCarrier ) then
  336.              connecting = 1
  337.           else
  338.              hangup = 1
  339.        end  /* Do */
  340.  
  341.        when abbrev( ResultCode, 'CONNECT' ) then do
  342.           if GoodCarrier( ResultCode, MinCarrier ) then
  343.              connected = 1
  344.           else
  345.              hangup = 1
  346.        end  /* Do */
  347.  
  348.        /* modem responses that indicate we should give up */
  349.  
  350.        when abbrev( ResultCode, 'ERROR' ) then exit 8
  351.        when abbrev( ResultCode, 'VOICE' ) then exit 8
  352.        when abbrev( ResultCode, 'DIGITAL LINE ERROR' ) then exit 8
  353.        when abbrev( ResultCode, 'RING' ) then exit 12
  354.  
  355.     otherwise do
  356.        /* The modem response was not recognized.... */
  357.        /* Can I query the serial port to check for DCD? */
  358.        /* If DCD is present, then who cares about the response? :-)  */
  359.             /* code to be developed */
  360.        /* DCD is NOT present, and the response was not recognized... */
  361.        /* ... so I don't know if the modem is on/off hook here :-(  */
  362.        call ResetModem
  363.        end /* otherwise */
  364.     end  /* select */
  365.  
  366.     if hangup then do
  367.        call lineout , 'Hanging up due unsatisfactory connection'
  368.        call ResetModem
  369.        connecting = 0
  370.        iterate
  371.     end  /* Do */
  372.  
  373.     if \connected then do
  374.        iterate
  375.     end
  376.  
  377.     /* OK.. all we've done so far is get the modems connected. */
  378.     /* If there is a "response file"... process it, otherwise try */
  379.     /* a "reasonable" combination of login and password prompts. */
  380.  
  381.     if RFile <> '' then do
  382.        call lineout , 'Continuing with response file... (' || RFile || ')'
  383.        if \ProcessRFile() then do
  384.           call ResetModem
  385.           iterate
  386.        end
  387.        call lineout , ' '
  388.        call lineout , 'Response file completed.'
  389.     end  /* Do */
  390.     else do
  391.        if \ProcessLogin() then do
  392.           call ResetModem
  393.           iterate
  394.        end
  395.        call lineout , ' '
  396.     end  /* Do */
  397.  
  398.     leave           /* force the end of the loop */
  399. end /* do */
  400.  
  401. if LogFile <> '' then do
  402.    /* the detail line already has the Date() and Time() we started dialing... */
  403.    /* now add the number of times we redialed and the elapsed time and final connect speed. */
  404.    DialingEndedAt = Time('S')
  405.    ElapsedTime = DialingEndedAt - DialingStartedAt
  406.    If ElapsedTime < 0 then
  407.       ElapsedTime = ElapsedTime + 86400
  408.    hour = ElapsedTime % 3600
  409.    minute = Right( ElapsedTime // 3600 % 60, 2, '0')
  410.    sec = Right( ElapsedTime // 3600 // 60, 2, '0')
  411.  
  412.    LogFileDetailLine = LogFileDetailLine count hour':'minute':'sec ActualCarrier
  413.    call lineout LogFile, LogFileDetailLine
  414. end /* do */
  415.  
  416. if count >=MaxAttempts then 
  417.    exit 4
  418.  
  419. if UseDialer then do
  420.    call lineout , VersionTag '- CONNECT' ActualCarrier '-' /* (start slippm V2.0 R1.8h timer) */
  421. end
  422.  
  423. if BeepWanted then do
  424.    call beep 262, 250
  425.    call beep 294, 250
  426. end
  427.  
  428. rc=0
  429. /* Call user exit... if present... */
  430. if stream( 'PPDXIT.CMD', 'C', 'QUERY EXISTS' ) <> '' then do
  431.    rc = ppdxit( ActualCarrier )
  432. end
  433.  
  434. exit rc
  435.  
  436. GoodCarrier:
  437.    /* examine the text following a CONNECT ... or CARRIER ... response code */
  438.    /* Even if no minimum carrier is requested, try to determine the actual */
  439.    /* DCE rate to report later. */
  440.  
  441.    do i = 2 to words( arg(1) )
  442.  
  443.       str = word( arg(1), i )
  444.  
  445.       x = verify( str, '0123456789', 'N' )
  446.       select
  447.          when x = 0 then /* all digits */
  448.             nop
  449.          when x = 1 then /* no digits  */
  450.             iterate i
  451.          otherwise       /* some digits */
  452.             str = left( str, x-1 )
  453.       end
  454.     
  455.       if str < 1200 then    /* just incase some modem reports a strange number */
  456.          iterate i
  457.  
  458.       if ActualCarrier = 0 then   /* set to min incase DCE and DTE are present */
  459.          ActualCarrier = str
  460.       else
  461.          ActualCarrier = min(str,ActualCarrier)
  462.  
  463.    end i /* do */
  464.  
  465.    return ( ActualCarrier >= arg(2) )
  466.  
  467. halt:
  468.    signal off halt
  469.    if RFile <> '' then
  470.       call lineout RFile /* close the response file */
  471.    if UsePhoneNumberFile then
  472.       call lineout PhoneNumberFile  /* close the phone number file */
  473.    call lineout , VersionTag 'cancelled.'
  474. exit 4
  475.  
  476. BuildDialCmd:
  477.    Parse arg item
  478.    DialCmd = Prefix            /* typically ATDT or ATDP */
  479.  
  480.    /* The phone number may be a group... get the next in the list/file */
  481.    x = (item // PhoneNo.0) + 1
  482.  
  483.    /* we only want the disable/prefix sequence if this is the whole number, or the first */
  484.    /* "phrase" of a multi-part number. */
  485.    if (\StartedDialing) then do
  486.       If Disable then
  487.          DialCmd = DialCmd || DisableSequence     /* a sequence to disable call waiting */
  488.       if DialPrefix <> '' then
  489.          DialCmd = DialCmd || DialPrefix || ','         /* a '9' or other for PBX */
  490.    end /* Do */
  491.  
  492.    return DialCmd || PhoneNo.x
  493.  
  494. ProcessLogin:
  495.    success = 1 /* we'll assume it works... */
  496.    call waitfor LoginPrompt, 30
  497.    if result = 1 then do
  498.       call lineout , 'Host is not asking for userid.'
  499.       success = 0
  500.    end  /* Do */
  501.    else do
  502.       call send loginId || cr
  503.  
  504.       call waitfor PasswordPrompt, 30
  505.       if result = 1 then do
  506.          call lineout , 'Host is not asking for password.'
  507.          success = 0
  508.       end  /* Do */
  509.  
  510.       call send password || cr
  511.    end /* do */
  512. return success
  513.  
  514. ProcessRFile:
  515.    RFileProcessed = 1         /* we'll assume success :-)  */
  516.    select
  517.       when RFile.1 = 'GO' then ResponseToggle = 1
  518.       when RFile.1 = 'WAIT' then ResponseToggle = 0
  519.    end  /* select */
  520.    do i = 2 to RFile.0 while RFileProcessed
  521.       x = RFile.i
  522.       if x = '' then     /* ignore blank lines */
  523.          iterate
  524.       if abbrev( x, '[PPPDIAL_' ) then    /* ignore parm settings */
  525.          iterate
  526.       if abbrev( x, '[OS/2]' ) then do
  527.          parse var x ']'os2Command
  528.          address CMD os2Command
  529.          iterate
  530.       end  /* Do */
  531.       if abbrev( x, '[SLEEP]' ) then do
  532.          parse var x ']'t
  533.          t = strip(t, 'B')
  534.          if t = '' then t = 1
  535.          if \datatype( t, 'W' ) then t = 1
  536.          call syssleep t
  537.          iterate
  538.       end  /* Do */
  539.  
  540.       if ResponseToggle then do
  541.           /* we are sending to the host... */
  542.           parse var x x1 '[' x2 ']' x3
  543.  
  544.           select
  545.              when x2 = 'LOGINID' then call send x1 || LoginId || x3 || cr
  546.              when x2 = 'PASSWORD' then do
  547.                  call send x1 || Password || x3 || cr
  548.                  call lineout , ' '
  549.                  end
  550.              when x2 = 'KEYBOARD' then do
  551.                  call beep 2000, 125     /* get attention for prompt */
  552.                  parse pull TheAnswer
  553.                  call send x1 || TheAnswer || x3 || cr
  554.              end  /* Do */
  555.              when x2 = 'KEYBOARD_NOECHO' then do
  556.                  call beep 2000, 125   /* get attention for prompt */
  557.                  TheAnswer = ''
  558.                  do until char = cr  /* wait for cr */
  559.                     char = SysGetKey( 'NOECHO' )
  560.                     if char = bs then do
  561.                        if TheAnswer = '' then call beep 2000, 125
  562.                           else do
  563.                              call charout , '082008'x   /* bs blank and bs */
  564.                              TheAnswer = delstr( TheAnswer, length( TheAnswer)  )
  565.                           end  /* Do */
  566.                    end  /* Do */
  567.                    else do
  568.                       if char = cr then
  569.                          call charout , crlf
  570.                       else do
  571.                          TheAnswer = TheAnswer || char
  572.                          call charout , '*'
  573.                       end /* Do */
  574.                   end /* Do */
  575.                  end /* Do */
  576.                  call send x1 || TheAnswer || x3 || cr
  577.                  drop TheAnswer  /* don't keep this data around any longer than necessary */
  578.              end  /* Do */
  579.              when abbrev( x, '[REPEAT]' ) then do
  580.                 parse var x ']' y z k     /* get string to send, string to wait for and count */
  581.                 if k = '' then k = 1000  /* repeat lots if not told otherwise */
  582.                 MatchFound = 0
  583.                 do k until MatchFound  /* successful match */
  584.                    select
  585.                       when pos( '^', y ) <> 0 then call send CtrlSequence( y )
  586.                       when y = '\r' then call send cr
  587.                    otherwise call send y || cr
  588.                    end  /* select */
  589.                    if waitfor( z , 5 ) = 0 then do /* successful match */
  590.                       MatchFound = 1
  591.                    end  /* Do */
  592.                 end /* until */
  593.                 if \MatchFound then do    /* retry count exhausted, no match found */
  594.                    RFileProcessed = 0     /* we encountered a problem... */
  595.                 end  /* Do */
  596.                 else do
  597.                    /* The string was repeated and we got the expected match... */
  598.                    /* I change the toggle so that it will be set to "send" again for */
  599.                    /* the next line in the response file. */
  600.                    ResponseToggle = \ResponseToggle
  601.                 end  /* Do */
  602.              end  /* when [REPEAT] */
  603.              when pos( '^', x) <> 0 then call send CtrlSequence( x )
  604.              when x = '\r' then call send cr
  605.           otherwise call send x || cr
  606.           end  /* select */
  607.           end
  608.       else do
  609.           /* It's our turn to wait for info from the host... */
  610.           /* before we just blindly wait for text, check to see if we're waiting */
  611.           /* for dynamic IP addresses... */
  612.           if pos( '[$IP', x ) > 0 then
  613.              call ProcessDynamicIP pos( '[$IPDEST]', x ), pos( '[$IPADDR]', x )
  614.           else
  615.           if abbrev( x, '[SKIP_TEXT]' ) then do forever
  616.              if PPPService then
  617.                 char = ppp_com_input( interface, 1, 100 )
  618.             else
  619.                 char = slip_com_input( interface, 1, 100 )
  620.             if (char >= ' ') | (char = lf) | (char = cr) then
  621.                 call charout , char
  622.             else
  623.                 leave
  624.           end  /* Do */
  625.           else
  626.           if waitfor( x, HostTimeout ) = 1 then do
  627.               call lineout , 'Host not responding, waiting for' x
  628.               RFileProcessed = 0   /* terminate processing and dial again :-(  */
  629.           end /* Do */
  630.       end /* Do */
  631.       ResponseToggle = \ResponseToggle
  632.    end /* While */
  633. return RFileProcessed
  634.  
  635. ProcessDynamicIP:
  636. /* We have two parms: */
  637. /* 1st: starting pos of [$IPDEST] */
  638. /* 2nd: starting pos of [$IPADDR] */
  639. /* These are just to indicate the order they appear from the host. */
  640. /* IP addresses must be in "decimal dot" notation */
  641.  
  642. parse arg dest, addr
  643. select
  644.    when dest = 0 then ipaddr = GetIPAddr()
  645.    when addr = 0 then ipdest = GetIPAddr()
  646.    when dest < addr then do
  647.       ipdest = GetIPAddr()
  648.       ipaddr = GetIPAddr()
  649.    end  /* Do */
  650.    when addr < dest then do
  651.       ipaddr = GetIPAddr()
  652.       ipdest = GetIPAddr()
  653.    end  /* Do */
  654. end  /* select */
  655.  
  656. if \PPPService then do
  657.    /* these don't seem to have any real effect when using PPP */
  658.    'ifconfig' interface ipaddr ipdest
  659.    'route add default' ipdest '1'
  660. end
  661.  
  662. return
  663.  
  664. GetIPAddr:
  665. /* examine data from the host system looking for an IP address */
  666. /* in "decimal dot" notation. Return the first one we get. */
  667. call time 'R'
  668. dot.1 = 0
  669. dot.2 = 0
  670. dot.3 = 0
  671. IPFound = 0
  672. IPTimeout = 30
  673. do until IPFound | time('E') > IPTimeOut
  674.    if PPPService then
  675.       remain_buffer = remain_buffer || ppp_com_input( interface, , 100 )
  676.    else
  677.       remain_buffer = remain_buffer || slip_com_input( interface, , 100 )
  678.    if dot.1 = 0 then do
  679.       dot.1 = pos( '.', remain_buffer )
  680.       if dot.1 = 0 then iterate
  681.    end  /* Do */
  682.  
  683.    /* "dot.1" is the index in remain_buffer to the first "." in a potential IP address */
  684.    if dot.2 = 0 then do
  685.       dot.2 = pos( '.', remain_buffer, dot.1 + 1 )
  686.       if dot.2 = 0 then iterate
  687.    end  /* Do */
  688.  
  689.    if dot.3 = 0 then do
  690.       dot.3 = pos( '.', remain_buffer, dot.2 + 1 )
  691.       if dot.3 = 0 then iterate
  692.    end  /* Do */
  693.  
  694.    PotentialIP = substr( remain_buffer, max( 1, dot.1 - 3 ) )
  695.    parse var PotentialIP a '.' b '.' c '.' d .
  696.    /* the "a" part MAY contain a space, we want the second part. */
  697.    if words(a) >1 then a = word( a, 2)
  698.  
  699.    /* the "d" part may not end with  digit. i.e. perhaps a ")" */
  700.    x = verify( d, '0123456789', 'N' )
  701.    if x <> 0 then do
  702.       d = substr( d, 1, x - 1 )
  703.    end  /* Do */
  704.  
  705.    if \datatype(a, 'W') | \datatype( b, 'W') | \datatype( c, 'W' ) | \datatype(d, 'W' ) then do
  706.       remain_buffer = substr( remain_buffer, dot.1 + 1 )
  707.       dot.1 = 0
  708.       dot.2 = 0
  709.       dot.3 = 0
  710.       iterate
  711.    end  /* Do */
  712.  
  713.    DecDot = a || '.' || b || '.' || c || '.' || d
  714.    IPFound = 1
  715.    remain_buffer = substr( remain_buffer, dot.3 + 2 )
  716. end /* do */
  717.  
  718. if IPFound then
  719.    call lineout , 'IP addr:' DecDot
  720. else
  721.    call lineout , 'IP addr: timed out'
  722.  
  723. return DecDot
  724.  
  725. ProcessRFileCommands:
  726.    success = 1   /* assume all is OK */
  727.    /* Build a stem variable for the parts required for the log in process. */
  728.    /* olny the relevent parts of the file will be added to the stem. */
  729.    /* Then the file is closed. */
  730.    i = 0
  731.    do while lines( RFile )
  732.       x = linein( RFile )
  733.       if x = '' then      /* ignore blank lines */
  734.          iterate
  735.       if \abbrev( x, '[PPPDIAL_' ) then do
  736.          i = i + 1
  737.          RFile.i = x
  738.          iterate
  739.       end
  740.       /* Only [PPPDIAL_...] lines are process here... */
  741.       parse var x '_'kw']'val
  742.       val = strip( val, 'B')
  743.       select
  744.          when kw = 'CARRIER_TIMEOUT' then ModemRegS7 = val
  745.          when kw = 'DELAY' then pause = val
  746.          when kw = 'DIAL_PREFIX' then DialPrefix = val
  747.          when kw = 'DO_NOT_USE_DIALER' then UseDialer = 0
  748.          when kw = 'HOST_TIMEOUT'  then HostTimeout = val
  749.          when kw = 'INIT1' then init1 = val
  750.          when kw = 'INIT2' then init2 = val
  751.          when kw = 'LOG' then LogFile = val
  752.          when kw = 'MAX_REDIAL' then MaxAttempts = val
  753.          when kw = 'MIN_CARRIER' then MinCarrier = val
  754.          when kw = 'MODEM_ESCAPE' then ModemEscapeSequence = val
  755.          when kw = 'MODEM_RESET' then ModemResetCommand = val
  756.          when kw = 'PHONE' then PhoneNumber = val
  757.          when kw = 'PREFIX' then Prefix = val
  758.          when kw = 'QUIET' then BeepWanted = 0
  759.          when kw = 'REM' then nop   /* allow comments... */
  760.          when kw = 'SERVICE' then PPPService = ( val = 'PPP' )
  761.          when kw = 'USE_DIALER' then UseDialer = 1
  762.       otherwise do
  763.          call lineout , kw 'is not a recognized keyword.'
  764.          success = 0
  765.       end /* otherwise */
  766.       end  /* select */
  767.    end /* while */
  768.    RFile.0 = i
  769.    call lineout RFile /* close the response file */
  770. return success
  771.  
  772. CtrlSequence:
  773.     parse arg string
  774.     /* we do a logical AND X'1F' with the character... */
  775.     /* The "character" should only be in the range of 40 through 5F, */
  776.     /* but who cares... the effect will be the same :-) */
  777.  
  778.     do until x = 0
  779.        x = pos( '^', string )
  780.        if x <> 0 then do
  781.           y = substr( string, x+1, 1)   /* isolate the character following ^ */
  782.           string = insert( bitand( y, '1F'x ), string, x+1 )
  783.           /* delete the character pair from the string */
  784.           string = delstr( string, x, 2 )
  785.       end /* Do */
  786.     end
  787.     return string
  788.  
  789. ResetModem:
  790.     call lineout , 'Initializing modem...'
  791.     if init1 <> '' then do
  792.        call send init1 || cr
  793.        ResultCode = GetResult( 6 )
  794.     end  /* Do */
  795.     if init2 <> '' then do
  796.        call send init2 || cr
  797.        ResultCode = GetResult( 6 )
  798.     end  /* Do */
  799.  
  800.     if ((init1 = '') & (init2 = '')) then do
  801.        call send ModemResetCommand || cr
  802.        ResultCode = GetResult( 6 )
  803.     end  /* Do */
  804.  
  805.     if left(ResultCode , 2) <> 'OK' then do
  806.         call lineout , 'Modem not resetting... Trying again'
  807.         call sysSleep 2
  808.         call send ModemEscapeSequence
  809.         call waitfor crlf, 5
  810.         call flush_receive
  811.         call ResetModem
  812.     end /* Do */
  813.     call flush_receive
  814. return
  815.  
  816. /* Routine to send a modem command. */
  817.  
  818. send:
  819.    parse arg AtCmd
  820.    call flush_receive
  821.    if PPPService then
  822.       call ppp_com_output interface , AtCmd
  823.    else
  824.       call slip_com_output interface , AtCmd
  825.    return
  826.  
  827. /* Waits for any modem response, and returns the string.    */
  828. /* If timeout is specified, it says how long to wait if data stops showing  */
  829. /* up on the COM port (in seconds).                                                         */
  830. getresult:
  831.    parse arg timeout
  832.    call waitfor crlf, timeout
  833.    if result = 0 then
  834.       call waitfor crlf, timeout
  835.  
  836.    if result = 1 then /* timed out */
  837.       return '*timedout*'
  838.    else
  839.       return waitfor_buffer
  840.  
  841.  
  842. /*--------------------------------------------------------------------------*/
  843. /*                    waitfor ( waitstring , [timeout] )                    */
  844. /*                                                                          */
  845. /* Waits for a specific string from the modem. */
  846. /* Timeout is specified in seconds.  */
  847. /* Ignore case... so login = LOGIN counts as a match... Added for version 3.0 */
  848.  
  849. waitfor:
  850.    parse upper arg waitstring , timeout
  851.    if timeout = '' then do
  852.       timeout = 90    /* 1.5 minutes if delay not specified */
  853.    end
  854.  
  855.    waitfor_buffer = ''
  856.    found = 0
  857.    expired = 0
  858.  
  859.    call time 'E'
  860.    do until (found | expired)
  861.       if PPPService then
  862.          chars = ppp_com_input( interface, , 10 )
  863.       else
  864.          chars = slip_com_input( interface, , 10 )
  865.       remain_buffer = Translate( remain_buffer || chars )
  866.       index = pos(waitstring, remain_buffer)
  867.       found = ( index > 0 )
  868.       expired = (time('E') > timeout)
  869.       if found then do
  870.          x = index + length(waitstring)
  871.          waitfor_buffer = delstr(remain_buffer, x)  /* everything up to what matched */
  872.          remain_buffer = substr(remain_buffer, x)  /* keep everything past that */
  873.       end
  874.       /* SLIPPM.EXE V2.0 R1.8h aborts our script when it "sees" certain words in the */
  875.       /* status window. Words like "BUSY", "NO CARRIER", etc. */
  876.       /* To get around this problem I translate all information from the modem */
  877.       /* to lower case, thus thwarting slippm's effort to detect what's going on. :-) */
  878.  
  879.       /* However, I don't know how long this will continue to work, because IBM is */
  880.       /* developing slippm and who knows what they have in mind for the next version? */
  881.  
  882.       call charout , translate(chars, LowerCase, UpperCase)
  883.    end
  884.  
  885.  return \found
  886.  
  887. /*--------------------------------------------------------------------------*/
  888. /*                             flush_receive()                             */
  889. /*                                                                          */
  890. /* Routine to flush any pending characters to be read from the COM port.    */
  891. /* Reads everything it can until nothing new shows up for 100ms, at which   */
  892. /* point it returns.                                                        */
  893. /*                                                                          */
  894. /*--------------------------------------------------------------------------*/
  895.  
  896. flush_receive:
  897.  
  898.    parse arg echo
  899.  
  900.    /* If echoing the flush - take care of waitfor remaining buffer */
  901.    /* Note - I translate the characters here to lower case to be consistent */
  902.    /* with the "waitfor" routine. (Due to slippm.exe V2.0 R1.8h changes) */
  903.  
  904.    if (echo <> '') & (length(remain_buffer) > 0) then do
  905.       call charout , translate( remain_buffer, LowerCase, UpperCase )
  906.       remain_buffer = ''
  907.    end
  908.  
  909.    /* Read anything left in the modem or COM buffers */
  910.    /* Stop when nothing new appears for 100ms.      */
  911.  
  912.    do until line = ''
  913.       if PPPservice then
  914.          line = ppp_com_input( interface,,100 )
  915.       else
  916.          line = slip_com_input( interface,,100 )
  917.       if echo <> '' then
  918.          call charout , translate( line, LowerCase, UpperCase )
  919.    end
  920.  
  921.    return
  922.  
  923. NotFromDialer:
  924.     parse upper source . . MyDrivePathName
  925.     MyDrive = filespec( 'D', MyDrivePathName )
  926.     MyPath = filespec( 'P', MyDrivePathName )
  927.     MyDrivePath = MyDrive || MyPath
  928.  
  929.     etcDrivePath = translate( value( 'etc',,'OS2ENVIRONMENT') )
  930.     binDrive = filespec( 'D', etcDrivePath )
  931.     binPath = filespec( 'P', etcDrivePath ) || 'BIN\'
  932.     binDrivePath = binDrive || binPath
  933.  
  934.     EraseFile = 0
  935.     if binDrivePath <> MyDrivePath then do
  936.         say 'This script will be moved to' binDrivePath
  937.         say 'Do you wish to continue? (y/n)'
  938.         say '(Saying no will still show help)'
  939.         answer = translate( sysGetKey( 'ECHO' ) )
  940.         if answer = 'Y' then do
  941.             'COPY' MyDrivePathName binDrivePath
  942.             if rc = 0 then do
  943.                say MyDrivePathName 'will be erased after displaying help'
  944.                EraseFile = 1
  945.             end
  946.            '@PAUSE'
  947.            call sysCls
  948.         end /* Do */
  949.     end  /* Do */
  950.  
  951.     call sysCls
  952.     stop = 0
  953.     do i = 3 by 1 until stop
  954.        x = sourceline( i )
  955.        if left( x, 5 ) = 'pause' then do
  956.           '@PAUSE'
  957.           call sysCls
  958.           iterate
  959.        end  /* Do */
  960.  
  961.        if left( x, 4 ) <> 'stop'  then
  962.           say x
  963.        else
  964.           stop = 1
  965.     end /* do */
  966.     '@PAUSE'
  967.     if EraseFile then
  968.         'ERASE' MyDrivePathName
  969. return
  970.