home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / duc10.zip / duc.cmd < prev    next >
OS/2 REXX Batch file  |  2003-01-03  |  23KB  |  1,037 lines

  1. /*
  2.  * DUC - Dial-Up Connection (duc.cmd)
  3.  *
  4.  * Establishes and kills dial-up connections relying on SLIPPM settings,
  5.  * the PPP executable, and a kill utility (provided).
  6.  *
  7.  * DUC circumvents the ugly and clunky GUI front end of DOIP/SLIPPM and
  8.  * creates program objects with slick icons. Click once to connect and
  9.  * another to disconnect.
  10.  *
  11.  * DUC is based on the proven PPP Connection Utilty by Walt Shekrota.
  12.  *
  13.  * Special DUC features:
  14.  *    - DUC icons (40x40).
  15.  *    - Kills PPP if already running (no need for CTRL-C).
  16.  *    - Object icon automatically synchronized if out-of-sync.
  17.  *    - Secondary name server may be specified.
  18.  *    - Inactivity timeout (hanging up).
  19.  *    - Sleep icon (indicating no activity).
  20.  *    - Total connect time updated.
  21.  * To come:
  22.  *    - Redial on busy and no carrier.
  23.  * Maybe:
  24.  *    - Logging
  25.  *
  26.  * Command syntax:
  27.  *    duc [ /create | /ns <server> | /beep ] <connection> [ <runthis> ]
  28.  *
  29.  * Where the switches:
  30.  *    /create creates a connection object on the desktop.
  31.  *    /ns <server> uses an additional name server as specified.
  32.  *    /beep beeps on connection, disconnection and buzzes on sleep.
  33.  *
  34.  * Where the values:
  35.  *    <connection> is the name (case-sensitive) of the connection.
  36.  *    <runthis> is passed to the start command.
  37.  *
  38.  * 1998-04-03  Original version as PPPCNT by Walt Shekrota
  39.  * 2002-12-18  Initial version as DUC by Magnus Olsson
  40.  * 2002-12-23  Synchronizes object icon if out-of-sync when the object
  41.  *             is opened.
  42.  * 2002-12-26  Uses pppkill. Added inactivity timeout (picked up from
  43.  *             DOIP and passed on to PPP along with other settings).
  44.  * 2002-12-27  Added some PPP options matching those used by DOIP:
  45.  *             modem, rtscts, priority 1, notify and exit.
  46.  * 2002-12-28  Idle time check (if timeout specified in DOIP): Shows
  47.  *             sleeping icon if no activity for a some time,
  48.  *             kills connection if timed out.
  49.  * 2002-12-29  Beeps some more.
  50.  * 2002-12-30  Kills dial command (slattach by default) along with PPP.
  51.  * 2002-12-31  Displays existing window if opened while not connected.
  52.  *             Handles halt signal.
  53.  *             Added interactive object creation.
  54.  * 2003-01-02  Cleaned up the code, removed superfluous tabs, etc.
  55.  *             Beeps longer on errors than on disconnections.
  56.  * 2003-01-03  Gives PPP a chance to terminate itself on halt.
  57.  */
  58.  
  59.  
  60. /*
  61.  * User Script Configuration
  62.  */
  63.  
  64. DIALUPICON= "dialup.ico"
  65. PROGRESSICON= "progress.ico"
  66. HANGUPICON= "hangup.ico"
  67. SLEEPICON= "sleep.ico"
  68. DIALCMD= "slattach"
  69.  
  70.  
  71. /*
  72.  * For DOIP hangup settings other than OFF
  73.  */
  74.  
  75. SLOWSTEP=   180  /* Seconds (at least) before registering sleep */
  76. QUICKSTEP=    3  /* Seconds (at the most) before switching back to active */
  77. NOISESTEP=   30  /* Seconds before repeating noise due to inactivity */
  78.  
  79.  
  80. /*
  81.  * Script return codes
  82.  */
  83.  
  84. RC_OK= 0
  85. RC_INI= 18  /* Initialization failed, e.g. no TCPOS2.INI */
  86. RC_CREATE= 19  /* Tried but could not create object */
  87. RC_SYNC= 21  /* Tried but could not synchronize object with connection state */
  88. RC_ABORT= 28  /* Started well, but had to abort */
  89. RC_HALT= 99  /* Halted by user */
  90.  
  91.  
  92. /*
  93.  * Object states showing different icons
  94.  */
  95.  
  96. DISCONNECTED= 'DISCONNECTED_ICON'
  97. RUNNING= 'RUNNING_ICON'
  98. CONNECTED= 'CONNECTED_ICON'
  99. SLEEPING= 'SLEEPING_ICON'
  100.  
  101.  
  102. /*
  103.  * PPP output (uppercased)
  104.  */
  105.  
  106. PPP_EXITING= 'EXITING...'
  107.  
  108.  
  109. /*
  110.  * Options (flags created as f<switch without slash> with '' indicating false)
  111.  */
  112.  
  113. opts.0= 3
  114. opts.1= '/create creates a connection object on the desktop'
  115. opts.2= '/ns <ns> specifies an additional name server'
  116. opts.3= '/beep beeps on connection established'
  117.  
  118.  
  119. /*
  120.  * Values (created as <name>)
  121.  */
  122.  
  123. vals.0= 2
  124. vals.1= 'connection'
  125. vals.2= 'runthis'
  126.  
  127.  
  128. /* Load OS/2 API functions */
  129.  
  130.  
  131. call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs"
  132. call SysLoadFuncs
  133.  
  134.  
  135. /* Initialize values and option switches to false or empty ('') */
  136.  
  137.  
  138. do val= 1 to vals.0 /* For each option in the list */
  139.     ditch= VALUE( vals.val, '' )
  140. end
  141.  
  142. do opt= 1 to opts.0 /* For each option in the list */
  143.     ditch= VALUE( 'f'SUBSTR( WORD( opts.opt, 1 ), 2 ), '' )
  144. end
  145.  
  146.  
  147. /* Parse command line (one word at a time) */
  148.  
  149.  
  150. val= 1
  151. lastval= vals.0
  152. fSwitchValue= 0
  153. argstr= ARG(1) /* Only one argument is possible */
  154. do wrd= 1 to WORDS(argstr) /* For each word in the argument string */
  155.     presword= WORD(argstr,wrd)
  156.     if SUBSTR(presword,1,1) = '/' then do /* We have a switch */
  157.         do opt= 1 to opts.0 /* For each option in the list */
  158.             /* Check if the word matches the option */
  159.             if presword = WORD( opts.opt, 1 ) then do /* We have a match */
  160.                 if POS( '<', opts.opt ) > 0 then do
  161.                     parse value opts.opt with optstr ' <'switchvalue'> ' definition
  162.                     fSwitchValue= 1
  163.                 end
  164.                 else do
  165.                     parse value opts.opt with optstr definition
  166.                     fSwitchValue= 0
  167.                 end
  168.                 ditch= VALUE( 'f'SUBSTR(optstr,2), definition )
  169.                 iterate wrd
  170.             end
  171.         end
  172.     end
  173.     /* No option matches -> assign value */
  174.     if fSwitchValue then do  /* Value associated with a switch */
  175.         ditch= VALUE( switchvalue, presword )
  176.         fSwitchValue= 0
  177.     end
  178.     else if val <= lastval then do  /* Ordered value */
  179.         ditch= VALUE( vals.val, presword )
  180.         prevval= presword
  181.         val= val + 1
  182.     end
  183.     else do  /* Concatenate remaining parameters for the last value */
  184.         ditch= VALUE( vals.lastval, prevval' 'presword )
  185.         prevval= prevval' 'presword
  186.     end
  187. end
  188.  
  189.  
  190. /* If no connection has been given assume interactive creation mode */
  191.  
  192. if connection = '' then do
  193.  
  194.     say 'Ready to create connection object.'
  195.  
  196.     say 'Enter name of connection exactly as it appears in DOIP: '
  197.  
  198.     parse linein connection params
  199.  
  200.     fCreate= 'INTERACTION'  /* Any non-empty value will do */
  201.  
  202. end
  203.  
  204.  
  205. /* Get the path info from where this cmd file is run */
  206.  
  207.  
  208. parse source . . this .
  209. this= Reverse(this)
  210. parse var this . '\' cmdpath .
  211. cmdpath= Reverse(cmdpath)
  212.  
  213.  
  214. /* Get INI file (parameters stored in TCPOS2.INI shared by DOIP and DUC) */
  215.  
  216.  
  217. inif= TcpChk(connection)
  218.  
  219. if inif = '' then do
  220.  
  221.     if fCreate = 'INTERACTION' then do
  222.  
  223.         say 'Press ENTER to exit'
  224.  
  225.         call Charin
  226.  
  227.     end
  228.  
  229.     exit RC_INI
  230.  
  231. end
  232.  
  233.  
  234. /*
  235.  * Choose track: Create object or run the current
  236.  */
  237.  
  238.  
  239. if fCreate <> '' then do
  240.  
  241.     if fCreate <> 'INTERACTION' then
  242.  
  243.         params= DELWORD( ARG( 1 ), WORDPOS( '/create', ARG( 1 ) ), 1 )
  244.  
  245.     else
  246.  
  247.         params= connection params
  248.  
  249.     if Create( DIALUPICON PROGRESSICON HANGUPICON SLEEPICON params ) then
  250.  
  251.         exit RC_OK
  252.  
  253.     else
  254.  
  255.         exit RC_CREATE
  256.  
  257.     if fCreate = 'INTERACTION' then do
  258.  
  259.         say 'Press ENTER to exit'
  260.  
  261.         call Charin
  262.  
  263.     end
  264.  
  265. end
  266.  
  267.  
  268. /*
  269.  * We are running
  270.  */
  271.  
  272.  
  273. state= SysIni( inif, connection, 'STATE' )  /* Gets object state */
  274.  
  275.  
  276. if RUNNING = state then
  277.  
  278.     say "Script may already be running in another process!"
  279.  
  280.  
  281. /* Clear queue */
  282.  
  283. do Queued(); Pull .; end
  284.  
  285.  
  286. /* Check for PPP and adapt accordingly */
  287.  
  288. pid= GetProcessId('PPP')
  289.  
  290. if pid <> 0 then do  /* PPP is running */
  291.  
  292.     /* Check for matching object state */
  293.  
  294.     if CONNECTED = state | SLEEPING = state then do  /* Match */
  295.  
  296.         /* Kill PPP by way of interface (ppp0) */
  297.  
  298.         say "PPP is running -> Killing connection!"
  299.  
  300.         call SetObjectIcon RUNNING
  301.  
  302.         '@pppkill ppp0'
  303.  
  304.         exit rc
  305.  
  306.     end
  307.  
  308.     else do /* State does not match */
  309.  
  310.         /* Synchronize by setting icon and updating state */
  311.  
  312.         if RUNNING = state then
  313.  
  314.             say "PPP is running -> Synchronizing Object!"
  315.  
  316.         else
  317.  
  318.             say "PPP is already running -> Synchronizing Object!"
  319.  
  320.         if SetObjectIcon( CONNECTED ) then
  321.  
  322.             exit RC_OK
  323.  
  324.         exit RC_SYNC
  325.  
  326.     end
  327.  
  328. end
  329.  
  330. else do /* PPP is not running */
  331.  
  332.     /* Check for matching object state */
  333.  
  334.     if DISCONNECTED = state then do /* Match */
  335.  
  336.         /* Change object icon to indicate we are running */
  337.  
  338.         say "PPP is not running -> Will try to establish connection!"
  339.  
  340.         call SetObjectIcon RUNNING
  341.  
  342.     end
  343.  
  344.     else do /* State does not match */
  345.  
  346.         /* Synchronize by setting icon and updating state */
  347.  
  348.         if RUNNING = state then
  349.  
  350.             say "PPP is not running -> Synchronizing Object!"
  351.  
  352.         else
  353.  
  354.             say "PPP is already not running -> Synchronizing Object!"
  355.  
  356.         if SetObjectIcon( DISCONNECTED ) then
  357.  
  358.             exit RC_OK /* Exit early */
  359.  
  360.         exit RC_SYNC
  361.  
  362.     end
  363.  
  364. end
  365.  
  366.  
  367. /*
  368.  * PPP is not running
  369.  */
  370.  
  371.  
  372. /* Set external interrupt handler */
  373.  
  374. signal on halt
  375.  
  376. say 'Enter CTRL-C or CTRL-BREAK to halt progress or break connection.'
  377.  
  378.  
  379. /* Maintain current/last connection names for newsreader */
  380.  
  381. ls= SysIni(inif, 'CONNECTION', 'CURRENT_CONNECTION') /* get last connect id */
  382.  
  383. if "ERROR:" = SysIni(inif,"CONNECTION","LAST_CONNECTION",ls) then
  384.     say "Error INI write LAST_CONNECTION"
  385. if "ERROR:" = SysIni(inif,"CONNECTION","CURRENT_CONNECTION",connection) then
  386.     say "Error INI write CURRENT_CONNECTION"
  387.  
  388.  
  389. /* Get domain name and server */
  390.  
  391. dn= SysIni(inif, connection, 'DOMAIN_NAME') /* get domain */
  392. ip= SysIni(inif, connection, 'DNS') /* get default nameserver IP addr */
  393.  
  394.  
  395. /* Update resolv file */
  396.  
  397. resolvfile= value(etc,,"OS2ENVIRONMENT")'\resolv'
  398. call LINEOUT resolvfile, "domain" STRIP(dn,'both',D2C(0)), 1
  399. call LINEOUT resolvfile, "nameserver" STRIP(ip,'both',D2C(0))
  400.  
  401. /* Add additional name server if passed on command line */
  402. if fNS <> '' then
  403.     call LINEOUT resolvfile, "nameserver" ns
  404.  
  405. /* Resolv file must be closed */
  406. call stream resolvfile, 'C', 'Close'
  407.  
  408.  
  409. /* Get remaining connection settings */
  410.  
  411. id= SysIni(inif, connection, 'LOGIN_ID')      /* login id       */
  412. id= Delstr(id, Length(id))
  413.  
  414. pwd= SysIni(inif, connection, 'PWD')           /* password       */
  415. pwd= Delstr(pwd, Length(pwd))
  416.  
  417. phone= SysIni(inif, connection, 'PHONE_NUMBER') /* Query the phonenumber */
  418. phone= Delstr(phone, Length(phone))
  419.  
  420. port= SysIni(inif, connection, 'COMPORT')     /* COM port used?        */
  421. port= Delstr(port, Length(port))
  422.  
  423. speed= SysIni(inif, connection, 'BAUD')       /* Linespeed?            */
  424. speed= Delstr(speed, Length(speed))
  425.  
  426. prefix= SysIni(inif, connection, 'PREFIX')    /* prefix dial tone/pulse*/
  427. prefix= Delstr(prefix, Length(prefix))
  428.  
  429. init1= SysIni(inif, connection, 'INIT')       /* init string 1         */
  430. init1= Delstr(init1, Length(init1))
  431.  
  432. init2= SysIni(inif, connection, 'INIT2')      /* init string 2         */
  433. init2= Delstr(init2, Length(init2))
  434.  
  435. mru= SysIni(inif, connection, 'MTU_SIZE')     /* MRU                   */
  436. mru= Delstr(mru, Length(mru))
  437.  
  438. script= SysIni(inif, connection, 'SCRIPT')    /* Connection script     */
  439. script= Delstr(script, Length(script))
  440.  
  441. dis= SysIni(inif, connection, 'DISABLE')      /* disable cw if 'TRUE'  */
  442. dis= Delstr(dis, Length(dis))
  443.  
  444. seq= SysIni(inif, connection, 'DISABLE_SEQ')  /* usually *70           */
  445. seq= Delstr(seq, Length(seq))
  446.  
  447. idle_timeout= SysIni(inif, connection, 'HANGUP')
  448. idle_timeout= Delstr(idle_timeout, Length(idle_timeout))
  449. if \DataType(idle_timeout,'Number') then
  450.     idle_timeout= 0
  451. else
  452.     idle_timeout= idle_timeout * 60  /* We want seconds */
  453.  
  454.  
  455. /* Modem init strings and expected responses */
  456.  
  457. if dis = 'TRUE' then phone= seq||phone    /* Call waiting */
  458.  
  459. if init1 = "" then str1= ""
  460. else str1= init1 "OK"
  461.  
  462. if init2 = "" then str2= ""
  463. else str2= init2 "OK"
  464.  
  465. str3= prefix||phone "NNECT"
  466.  
  467.  
  468. /* Connection script, insert id and password */
  469.  
  470. if script <> 'NONE' then do
  471.     chrs= "0d0a"x
  472.     script= Translate(script,"  ",chrs)
  473.     script= ReplaceIf(script,"[LOGINID]",id)
  474.     script= ReplaceIf(script,"[PASSWORD]",pwd)
  475.     str3= str3 script
  476.     name_and_pwd= ""
  477. end
  478. else
  479.     name_and_pwd= "name" id "secret" pwd
  480.  
  481.  
  482. /* PPP serial line attach connect command string */
  483.  
  484. connect_string= '"'dialcmd str1 str2 str3'"'
  485.  
  486.  
  487. /* Various PPP options */
  488.  
  489. ppp_opts= port speed 'mru' mru 'modem rtscts defaultroute priority 1 notify exit'
  490.  
  491.  
  492. /* Bring it all together */
  493.  
  494. ppp_args= ppp_opts name_and_pwd 'connect' connect_string
  495.  
  496.  
  497. /*
  498.  * Start PPP in another process and wait for connection ready
  499.  */
  500.  
  501.  
  502. start_opts= '/i /c /min' /* Inherit environment, use cmd.exe, background, minimized */
  503. start_params= '"PPP ('connection')"' start_opts 'ducppp' connection ppp_args
  504.  
  505.  
  506. /* Create named queue for lack of better IPC */
  507.  
  508. call RXQueue 'Create', connection'Queue'
  509.  
  510.  
  511. /* Finally ready to run PPP */
  512.  
  513. say 'Starting: 'start_params
  514.  
  515. '@start 'start_params
  516.  
  517.  
  518. /* Use connection queue */
  519.  
  520. default_queue= RXQueue( 'Set', connection'Queue' )
  521.  
  522.  
  523. /* Wait for PPP to give its ready signal */
  524.  
  525. fExiting= 0
  526. fConnected= 0
  527. do while \fConnected
  528.     do QUEUED()
  529.         pull line
  530.         parse var line '['special']'
  531.         if special <> '' then do
  532.             if special = 'PPP' then do
  533.                 call Time 'Reset'  /* Start connection timer */
  534.                 fConnected= 1
  535.                 leave
  536.             end
  537.             else if special = 'ENDED' then do
  538.                 if fExiting then
  539.                     call Abort 'PPP Driver Ended Prematurely (No Connection Established)'
  540.                 else
  541.                     call Abort 'PPP Driver Failure'
  542.             end
  543.             else
  544.                 say '['special']'
  545.         end
  546.         else if Pos( PPP_EXITING, line ) <> 0 then
  547.             fExiting= 1
  548.         else
  549.             say line
  550.     end
  551.     call SysSleep 1
  552. end
  553.  
  554.  
  555. /*
  556.  * We are connected!
  557.  */
  558.  
  559.  
  560. say "PPP Connection Established."
  561.  
  562.  
  563. /* Switch to connected icon */
  564.  
  565. call SetObjectIcon CONNECTED, fBeep
  566.  
  567.  
  568. /*
  569.  * Start any application passed
  570.  */
  571.  
  572.  
  573. if runthis <> '' then do
  574.  
  575.     say 'Starting: 'runthis
  576.  
  577.     address CMD 'start' runthis
  578.  
  579. end
  580.  
  581.  
  582. /*
  583.  * Run a low intensity loop checking for idle time
  584.  */
  585.  
  586.  
  587. check_time= 0
  588. traffic_time= 0
  589. noise_time= 0
  590. last_bytesum= 0
  591. step= SLOWSTEP
  592. fDisconnected= 0
  593. do while \fDisconnected
  594.     tcps_sndbyte= ''
  595.     tcps_rcvbyte= ''
  596.     this_bytesum= ''
  597.     do QUEUED()  /* Deplete queue if any */
  598.         pull line
  599.         parse var line '['special']'
  600.         if special <> '' then do
  601.             if special = 'ENDED' then do
  602.                 fDisconnected= 1
  603.                 leave
  604.             end
  605.             else
  606.                 say '['special']'
  607.         end
  608.         else if this_bytesum = '' then do
  609.             if tcps_sndbyte = '' then
  610.                 parse var line . "DATA BYTES SENT "tcps_sndbyte
  611.             else if tcps_rcvbyte = '' then
  612.                 parse var line . "BYTES RECEIVED IN SEQUENCE "tcps_rcvbyte
  613.             else
  614.                 this_bytesum= tcps_sndbyte + tcps_rcvbyte
  615.         end
  616.     end
  617.     if idle_timeout > 0 then do
  618.         this_time= Time('Elapsed')
  619.         if ( this_time - check_time ) > step then do  /* Time to check traffic */
  620.             if this_bytesum = '' then do  /* Need traffic data */
  621.                 '@netstat -tcp | RXQueue' connection'Queue'
  622.                 iterate
  623.             end
  624.             check_time= this_time
  625.             if this_bytesum <> last_bytesum then do  /* We have had some traffic */
  626.                 if step = QUICKSTEP then do  /* We have come around */
  627.                     step= SLOWSTEP
  628.                     call SetObjectIcon CONNECTED
  629.                     say 'Waking up with' this_bytesum 'bytes in traffic.'
  630.                 end
  631.                 traffic_time= this_time
  632.                 last_bytesum= this_bytesum
  633.             end
  634.             else do  /* No traffic since last time */
  635.                 idle_time= this_time - traffic_time
  636.                 if step = SLOWSTEP then do  /* We have just fallen asleep */
  637.                     step= QUICKSTEP
  638.                     call SetObjectIcon SLEEPING
  639.                     say 'Falling asleep after' this_bytesum 'bytes in traffic.'
  640.                 end
  641.                 else if idle_time > idle_timeout then do  /* We have been idle too long time */
  642.                     say 'Killing connection due to inactivity.'
  643.                     call SetObjectIcon RUNNING
  644.                     '@pppkill ppp0'
  645.                     leave
  646.                 end
  647.                 else do  /* No change of state */
  648.                     if ( this_time - noise_time ) > NOISESTEP then do  /* Just noise */
  649.                         noise_time= this_time
  650.                         if ( idle_time + ( NOISESTEP * 3 ) ) > idle_timeout then do
  651.                             say 'Warning: Close to killing connection due to inactivity ('Trunc(idle_timeout-idle_time)' seconds remaining).'
  652.                             call Beep 1440, 180; call Beep 1440, 180; call Beep 1440, 180
  653.                         end
  654.                         else if fBeep <> '' then /* Still sleeping */
  655.                             call Beep 45, 270
  656.                     end
  657.                 end
  658.             end
  659.         end
  660.     end
  661.     call SysSleep 1
  662. end
  663.  
  664.  
  665. /*
  666.  * Connection ended without error
  667.  */
  668.  
  669.  
  670. connected_time= Trunc(Time('Elapsed'))  /* Whole seconds only */
  671.  
  672. say 'PPP Connection Ended (Time online 'connected_time' seconds).'
  673.  
  674.  
  675. /* Restore object to disconnected state and update total connect time */
  676.  
  677. say 'Restoring icon and state to disconnected...'
  678.  
  679. if SetObjectIcon( DISCONNECTED, fBeep ) then do
  680.  
  681.     if connected_time <> '' then do
  682.  
  683.         /* Update total connection time */
  684.  
  685.         total_connect= STRIP( SysIni( inif, connection, 'TOTAL_CONNECT' ), 'both', D2C(0) )
  686.  
  687.         if \DataType( total_connect, 'N') | \DataType( connected_time, 'N') then do
  688.  
  689.             say 'Not valid numbers: 'total_connect', 'connect_seconds
  690.  
  691.             return connected_time
  692.  
  693.         end
  694.  
  695.         total_connect= total_connect + connected_time
  696.  
  697.         if 'ERROR:' = SysIni( inif, connection, 'TOTAL_CONNECT', total_connect ) then do
  698.  
  699.             say 'Error writing INI file ('inif').'
  700.  
  701.             return total_connect
  702.  
  703.          end
  704.  
  705.     end
  706.  
  707.     say 'Icon and state restored OK.'
  708.  
  709. end
  710.  
  711.  
  712. /* Remove resolv file */
  713.  
  714. '@erase' value(etc,,"OS2ENVIRONMENT")'\resolv'
  715.  
  716.  
  717. /*
  718.  * We are done -> Clean up
  719.  */
  720.  
  721.  
  722. Terminate:
  723.  
  724.     /* Delete named queue */
  725.  
  726.     call RXQueue 'Delete', connection'Queue'
  727.  
  728.     exit rc
  729.  
  730.  
  731.  
  732. /* ---------------------------
  733.  * Subroutines (fully exposed)
  734.  */
  735.  
  736.  
  737.  
  738. Create:
  739. /*
  740.    Create PPP connection objects on desktop.
  741.  
  742.    To specify custom icons order is important ... stop, caution, go
  743.  
  744.    Returns 1 on success, and 0 otherwise.
  745. */
  746.  
  747.     parse arg dialupico progressico hangupico sleepico params
  748.  
  749.     /* If custom icons ALL must be set or defaults will be used  */
  750.  
  751.     if dialupico = '' | progressico = '' | hangupico = '' then do
  752.         dialupico= DIALUPICON
  753.         progressico= PROGRESSICON
  754.         hangupico= HANGUPICON
  755.     end
  756.     if sleepico = '' then
  757.         sleepico= hangupico
  758.  
  759.     /*
  760.      * Write icon names and initial state out to TCPOS2 for account
  761.      */
  762.  
  763.     fComplete= 0
  764.     if "ERROR:" = SysIni(inif,connection,DISCONNECTED,dialupico) then
  765.         say "Error INI write disconnected icon"
  766.     else
  767.         if "ERROR:" = SysIni(inif,connection,RUNNING,progressico) then
  768.             say "Error INI write running icon"
  769.         else
  770.             if "ERROR:" = SysIni(inif,connection,CONNECTED,hangupico) then
  771.                 say "Error INI write connected icon"
  772.             else
  773.                 if "ERROR:" = SysIni(inif,connection,SLEEPING,sleepico) then
  774.                     say "Error INI write sleeping icon"
  775.                 else
  776.                     fComplete= 1
  777.  
  778.     if \fComplete then do
  779.  
  780.         say "Error writing to ini file."
  781.  
  782.         return 0
  783.  
  784.     end
  785.  
  786.     /*
  787.      * Create connection object on desktop
  788.      */
  789.  
  790.     /* Executable settings */
  791.     setup= 'EXENAME='cmdpath'\duc.cmd;PARAMETERS='params '%'
  792.  
  793.     /* Object settings (window) */
  794.     setup= setup || ';MINIMIZED=YES;CCVIEW=NO'
  795.  
  796.     result= SysCreateObject('WPProgram',connection,'<WP_DESKTOP>','OBJECTID=<'Substr(connection,1,8,"_")'>;'setup,'R')
  797.  
  798.     if result then do
  799.  
  800.         call SetObjectIcon DISCONNECTED
  801.  
  802.         say connection 'object created on desktop (move as you see fit).'
  803.  
  804.     end
  805.  
  806.     else
  807.  
  808.         say "Difficulty creating" connection "object on desktop."
  809.  
  810.     return result
  811.  
  812.  
  813.  
  814. Abort:
  815. /*
  816.     Abnormal condition, indicate error, restore object icon and terminate!
  817. */
  818.     parse arg string
  819.  
  820.     if string <> '' then
  821.  
  822.         say string'.'
  823.  
  824.     call Beep 999, 450
  825.  
  826.     call SurfaceObject
  827.  
  828.     say 'Press ENTER to exit.'
  829.  
  830.     call Charin
  831.  
  832.     call SetObjectIcon DISCONNECTED
  833.  
  834.     rc= RC_ABORT
  835.  
  836.     call Terminate
  837.  
  838.  
  839.  
  840. Halt:
  841. /*
  842.     Handler for external attempts to interrupt and end execution.
  843.  
  844.     Kill started processes, restore object and terminate.
  845. */
  846.  
  847.     say 'Halting...'
  848.  
  849.     /* Use default queue (if queue changed earlier) */
  850.  
  851.     if Symbol( 'default_queue' ) = 'VAR' then
  852.  
  853.         call RXQueue 'Set', default_queue
  854.  
  855.    /* Kill dial command if running */
  856.  
  857.     pid= GetProcessId(DIALCMD)
  858.  
  859.     if pid <> 0 then do  /* Dial command is running */
  860.  
  861.         say DIALCMD "is running -> Killing its process!"
  862.  
  863.         '@kill' pid
  864.  
  865.         call SysSleep 1  /* Give PPP a chance to terminate itself */
  866.  
  867.     end
  868.  
  869.    /* Kill PPP if still running */
  870.  
  871.     pid= GetProcessId(PPP)
  872.  
  873.     if pid <> 0 then do  /* Dial command is running */
  874.  
  875.         say "PPP is running -> Killing its process!"
  876.  
  877.         '@kill' pid
  878.  
  879.     end
  880.  
  881.    /* Restore object */
  882.  
  883.     call SetObjectIcon DISCONNECTED, fBeep
  884.  
  885.     say 'Halted.'
  886.  
  887.     rc= RC_HALT
  888.  
  889.     call Terminate
  890.  
  891.  
  892.  
  893. SetObjectIcon:
  894. /*
  895.     Sets the icon of the current connection object.
  896.  
  897.     Takes state and beeps on steady states if flagged.
  898.  
  899.     Returns 1 if icon has been set, and 0 otherwise.
  900. */
  901.  
  902.     arg state, fBeepFlag
  903.  
  904.     iconfile= cmdpath'\'SysIni( inif, connection, state )
  905.  
  906.     if "ERROR:" = iconfile then return 0
  907.  
  908.     if SysSetObjectData( '<'Substr(connection,1,8,'_')'>', "ICONFILE="iconfile ) then do
  909.  
  910.         call SysIni inif, connection, 'STATE', state
  911.  
  912.         if state = CONNECTED then do
  913.  
  914.             call SetObjectCCView 'Yes'
  915.  
  916.             if fBeepFlag <> '' then call Beep 1440, 180
  917.  
  918.         end
  919.  
  920.         else if state = DISCONNECTED then do
  921.  
  922.             call SetObjectCCView 'No'
  923.  
  924.             if fBeepFlag <> '' then call Beep 900, 270
  925.  
  926.         end
  927.  
  928.         return 1
  929.  
  930.     end
  931.  
  932.     else
  933.  
  934.         return 0
  935.  
  936.  
  937.  
  938. SetObjectCCView:
  939. /*
  940.     Sets the CCView setting of the current connection object.
  941.  
  942.     Takes 'Yes' or 'No' for setting (case does not matter).
  943.  
  944.     Returns 1 if setting has been set, and 0 otherwise.
  945. */
  946.  
  947.     arg setting
  948.  
  949.     if SysSetObjectData( '<'Substr(connection,1,8,'_')'>', "CCVIEW="setting ) then
  950.  
  951.         return 1
  952.  
  953.     else
  954.  
  955.         return 0
  956.  
  957.  
  958.  
  959. SurfaceObject:
  960. /*
  961.     Surfaces existing window of the current connection object.
  962.  
  963.     Returns 1 if setting has been set, and 0 otherwise.
  964. */
  965.  
  966.     arg setting
  967.  
  968.     if SysOpenObject( '<'Substr(connection,1,8,'_')'>', "DEFAULT", "TRUE" ) then
  969.  
  970.         return 1
  971.  
  972.     else
  973.  
  974.         return 0
  975.  
  976.  
  977.  
  978. /* ----------
  979.  * Procedures
  980.  */
  981.  
  982.  
  983.  
  984. TcpChk: PROCEDURE
  985. /*
  986.     Checks that passed account exists and is valid.
  987.  
  988.     Returns INI file if OK, otherwise the empty string is returned.
  989. */
  990.  
  991.     Parse Arg account .
  992.  
  993.     /* Look for TCPOS2.INI file */
  994.  
  995.     inif= SysSearchPath("ETC", "tcpos2.ini")
  996.     if inif = '' then do
  997.         say "TCPOS2.INI file not found, perhaps TCP/IP is not installed."
  998.         return ""
  999.     end
  1000.  
  1001.     /* This account found in TCPOS2.INI? */
  1002.  
  1003.     type= SysIni(inif, account, 'SERVICE')  /* test INI for account  */
  1004.     if type = 'ERROR:' then do
  1005.         say "Create" account "in Dial Other Internet Providers, account not found."
  1006.         return ""
  1007.     end
  1008.     type= DELSTR(type, LENGTH(type))
  1009.  
  1010.     /* Service set for SLIP or PPP (must be the latter)? */
  1011.  
  1012.     if type <> 'PPP' then do
  1013.         say "Check" account "in Dial Other Internet Providers, not a PPP account!"
  1014.         return ""
  1015.     end
  1016.  
  1017.     return inif
  1018.  
  1019.  
  1020.  
  1021. GetProcessId: PROCEDURE
  1022. /*
  1023.     Returns process id (in decimal format) of executable given without extension.
  1024. */
  1025.     arg exesought
  1026.  
  1027.     '@pstat /c | RXQueue'
  1028.  
  1029.     do QUEUED()
  1030.         pull pid . . exefound'.EXE' something
  1031.         if ( something <> '' ) & ( Pos( exesought, exefound ) <> 0 ) then
  1032.             return X2D(pid)
  1033.     end
  1034.  
  1035.     return 0
  1036.  
  1037.