home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 18 REXX
/
18-REXX.zip
/
duc10.zip
/
duc.cmd
< prev
next >
Wrap
OS/2 REXX Batch file
|
2003-01-03
|
23KB
|
1,037 lines
/*
* DUC - Dial-Up Connection (duc.cmd)
*
* Establishes and kills dial-up connections relying on SLIPPM settings,
* the PPP executable, and a kill utility (provided).
*
* DUC circumvents the ugly and clunky GUI front end of DOIP/SLIPPM and
* creates program objects with slick icons. Click once to connect and
* another to disconnect.
*
* DUC is based on the proven PPP Connection Utilty by Walt Shekrota.
*
* Special DUC features:
* - DUC icons (40x40).
* - Kills PPP if already running (no need for CTRL-C).
* - Object icon automatically synchronized if out-of-sync.
* - Secondary name server may be specified.
* - Inactivity timeout (hanging up).
* - Sleep icon (indicating no activity).
* - Total connect time updated.
* To come:
* - Redial on busy and no carrier.
* Maybe:
* - Logging
*
* Command syntax:
* duc [ /create | /ns <server> | /beep ] <connection> [ <runthis> ]
*
* Where the switches:
* /create creates a connection object on the desktop.
* /ns <server> uses an additional name server as specified.
* /beep beeps on connection, disconnection and buzzes on sleep.
*
* Where the values:
* <connection> is the name (case-sensitive) of the connection.
* <runthis> is passed to the start command.
*
* 1998-04-03 Original version as PPPCNT by Walt Shekrota
* 2002-12-18 Initial version as DUC by Magnus Olsson
* 2002-12-23 Synchronizes object icon if out-of-sync when the object
* is opened.
* 2002-12-26 Uses pppkill. Added inactivity timeout (picked up from
* DOIP and passed on to PPP along with other settings).
* 2002-12-27 Added some PPP options matching those used by DOIP:
* modem, rtscts, priority 1, notify and exit.
* 2002-12-28 Idle time check (if timeout specified in DOIP): Shows
* sleeping icon if no activity for a some time,
* kills connection if timed out.
* 2002-12-29 Beeps some more.
* 2002-12-30 Kills dial command (slattach by default) along with PPP.
* 2002-12-31 Displays existing window if opened while not connected.
* Handles halt signal.
* Added interactive object creation.
* 2003-01-02 Cleaned up the code, removed superfluous tabs, etc.
* Beeps longer on errors than on disconnections.
* 2003-01-03 Gives PPP a chance to terminate itself on halt.
*/
/*
* User Script Configuration
*/
DIALUPICON= "dialup.ico"
PROGRESSICON= "progress.ico"
HANGUPICON= "hangup.ico"
SLEEPICON= "sleep.ico"
DIALCMD= "slattach"
/*
* For DOIP hangup settings other than OFF
*/
SLOWSTEP= 180 /* Seconds (at least) before registering sleep */
QUICKSTEP= 3 /* Seconds (at the most) before switching back to active */
NOISESTEP= 30 /* Seconds before repeating noise due to inactivity */
/*
* Script return codes
*/
RC_OK= 0
RC_INI= 18 /* Initialization failed, e.g. no TCPOS2.INI */
RC_CREATE= 19 /* Tried but could not create object */
RC_SYNC= 21 /* Tried but could not synchronize object with connection state */
RC_ABORT= 28 /* Started well, but had to abort */
RC_HALT= 99 /* Halted by user */
/*
* Object states showing different icons
*/
DISCONNECTED= 'DISCONNECTED_ICON'
RUNNING= 'RUNNING_ICON'
CONNECTED= 'CONNECTED_ICON'
SLEEPING= 'SLEEPING_ICON'
/*
* PPP output (uppercased)
*/
PPP_EXITING= 'EXITING...'
/*
* Options (flags created as f<switch without slash> with '' indicating false)
*/
opts.0= 3
opts.1= '/create creates a connection object on the desktop'
opts.2= '/ns <ns> specifies an additional name server'
opts.3= '/beep beeps on connection established'
/*
* Values (created as <name>)
*/
vals.0= 2
vals.1= 'connection'
vals.2= 'runthis'
/* Load OS/2 API functions */
call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs"
call SysLoadFuncs
/* Initialize values and option switches to false or empty ('') */
do val= 1 to vals.0 /* For each option in the list */
ditch= VALUE( vals.val, '' )
end
do opt= 1 to opts.0 /* For each option in the list */
ditch= VALUE( 'f'SUBSTR( WORD( opts.opt, 1 ), 2 ), '' )
end
/* Parse command line (one word at a time) */
val= 1
lastval= vals.0
fSwitchValue= 0
argstr= ARG(1) /* Only one argument is possible */
do wrd= 1 to WORDS(argstr) /* For each word in the argument string */
presword= WORD(argstr,wrd)
if SUBSTR(presword,1,1) = '/' then do /* We have a switch */
do opt= 1 to opts.0 /* For each option in the list */
/* Check if the word matches the option */
if presword = WORD( opts.opt, 1 ) then do /* We have a match */
if POS( '<', opts.opt ) > 0 then do
parse value opts.opt with optstr ' <'switchvalue'> ' definition
fSwitchValue= 1
end
else do
parse value opts.opt with optstr definition
fSwitchValue= 0
end
ditch= VALUE( 'f'SUBSTR(optstr,2), definition )
iterate wrd
end
end
end
/* No option matches -> assign value */
if fSwitchValue then do /* Value associated with a switch */
ditch= VALUE( switchvalue, presword )
fSwitchValue= 0
end
else if val <= lastval then do /* Ordered value */
ditch= VALUE( vals.val, presword )
prevval= presword
val= val + 1
end
else do /* Concatenate remaining parameters for the last value */
ditch= VALUE( vals.lastval, prevval' 'presword )
prevval= prevval' 'presword
end
end
/* If no connection has been given assume interactive creation mode */
if connection = '' then do
say 'Ready to create connection object.'
say 'Enter name of connection exactly as it appears in DOIP: '
parse linein connection params
fCreate= 'INTERACTION' /* Any non-empty value will do */
end
/* Get the path info from where this cmd file is run */
parse source . . this .
this= Reverse(this)
parse var this . '\' cmdpath .
cmdpath= Reverse(cmdpath)
/* Get INI file (parameters stored in TCPOS2.INI shared by DOIP and DUC) */
inif= TcpChk(connection)
if inif = '' then do
if fCreate = 'INTERACTION' then do
say 'Press ENTER to exit'
call Charin
end
exit RC_INI
end
/*
* Choose track: Create object or run the current
*/
if fCreate <> '' then do
if fCreate <> 'INTERACTION' then
params= DELWORD( ARG( 1 ), WORDPOS( '/create', ARG( 1 ) ), 1 )
else
params= connection params
if Create( DIALUPICON PROGRESSICON HANGUPICON SLEEPICON params ) then
exit RC_OK
else
exit RC_CREATE
if fCreate = 'INTERACTION' then do
say 'Press ENTER to exit'
call Charin
end
end
/*
* We are running
*/
state= SysIni( inif, connection, 'STATE' ) /* Gets object state */
if RUNNING = state then
say "Script may already be running in another process!"
/* Clear queue */
do Queued(); Pull .; end
/* Check for PPP and adapt accordingly */
pid= GetProcessId('PPP')
if pid <> 0 then do /* PPP is running */
/* Check for matching object state */
if CONNECTED = state | SLEEPING = state then do /* Match */
/* Kill PPP by way of interface (ppp0) */
say "PPP is running -> Killing connection!"
call SetObjectIcon RUNNING
'@pppkill ppp0'
exit rc
end
else do /* State does not match */
/* Synchronize by setting icon and updating state */
if RUNNING = state then
say "PPP is running -> Synchronizing Object!"
else
say "PPP is already running -> Synchronizing Object!"
if SetObjectIcon( CONNECTED ) then
exit RC_OK
exit RC_SYNC
end
end
else do /* PPP is not running */
/* Check for matching object state */
if DISCONNECTED = state then do /* Match */
/* Change object icon to indicate we are running */
say "PPP is not running -> Will try to establish connection!"
call SetObjectIcon RUNNING
end
else do /* State does not match */
/* Synchronize by setting icon and updating state */
if RUNNING = state then
say "PPP is not running -> Synchronizing Object!"
else
say "PPP is already not running -> Synchronizing Object!"
if SetObjectIcon( DISCONNECTED ) then
exit RC_OK /* Exit early */
exit RC_SYNC
end
end
/*
* PPP is not running
*/
/* Set external interrupt handler */
signal on halt
say 'Enter CTRL-C or CTRL-BREAK to halt progress or break connection.'
/* Maintain current/last connection names for newsreader */
ls= SysIni(inif, 'CONNECTION', 'CURRENT_CONNECTION') /* get last connect id */
if "ERROR:" = SysIni(inif,"CONNECTION","LAST_CONNECTION",ls) then
say "Error INI write LAST_CONNECTION"
if "ERROR:" = SysIni(inif,"CONNECTION","CURRENT_CONNECTION",connection) then
say "Error INI write CURRENT_CONNECTION"
/* Get domain name and server */
dn= SysIni(inif, connection, 'DOMAIN_NAME') /* get domain */
ip= SysIni(inif, connection, 'DNS') /* get default nameserver IP addr */
/* Update resolv file */
resolvfile= value(etc,,"OS2ENVIRONMENT")'\resolv'
call LINEOUT resolvfile, "domain" STRIP(dn,'both',D2C(0)), 1
call LINEOUT resolvfile, "nameserver" STRIP(ip,'both',D2C(0))
/* Add additional name server if passed on command line */
if fNS <> '' then
call LINEOUT resolvfile, "nameserver" ns
/* Resolv file must be closed */
call stream resolvfile, 'C', 'Close'
/* Get remaining connection settings */
id= SysIni(inif, connection, 'LOGIN_ID') /* login id */
id= Delstr(id, Length(id))
pwd= SysIni(inif, connection, 'PWD') /* password */
pwd= Delstr(pwd, Length(pwd))
phone= SysIni(inif, connection, 'PHONE_NUMBER') /* Query the phonenumber */
phone= Delstr(phone, Length(phone))
port= SysIni(inif, connection, 'COMPORT') /* COM port used? */
port= Delstr(port, Length(port))
speed= SysIni(inif, connection, 'BAUD') /* Linespeed? */
speed= Delstr(speed, Length(speed))
prefix= SysIni(inif, connection, 'PREFIX') /* prefix dial tone/pulse*/
prefix= Delstr(prefix, Length(prefix))
init1= SysIni(inif, connection, 'INIT') /* init string 1 */
init1= Delstr(init1, Length(init1))
init2= SysIni(inif, connection, 'INIT2') /* init string 2 */
init2= Delstr(init2, Length(init2))
mru= SysIni(inif, connection, 'MTU_SIZE') /* MRU */
mru= Delstr(mru, Length(mru))
script= SysIni(inif, connection, 'SCRIPT') /* Connection script */
script= Delstr(script, Length(script))
dis= SysIni(inif, connection, 'DISABLE') /* disable cw if 'TRUE' */
dis= Delstr(dis, Length(dis))
seq= SysIni(inif, connection, 'DISABLE_SEQ') /* usually *70 */
seq= Delstr(seq, Length(seq))
idle_timeout= SysIni(inif, connection, 'HANGUP')
idle_timeout= Delstr(idle_timeout, Length(idle_timeout))
if \DataType(idle_timeout,'Number') then
idle_timeout= 0
else
idle_timeout= idle_timeout * 60 /* We want seconds */
/* Modem init strings and expected responses */
if dis = 'TRUE' then phone= seq||phone /* Call waiting */
if init1 = "" then str1= ""
else str1= init1 "OK"
if init2 = "" then str2= ""
else str2= init2 "OK"
str3= prefix||phone "NNECT"
/* Connection script, insert id and password */
if script <> 'NONE' then do
chrs= "0d0a"x
script= Translate(script," ",chrs)
script= ReplaceIf(script,"[LOGINID]",id)
script= ReplaceIf(script,"[PASSWORD]",pwd)
str3= str3 script
name_and_pwd= ""
end
else
name_and_pwd= "name" id "secret" pwd
/* PPP serial line attach connect command string */
connect_string= '"'dialcmd str1 str2 str3'"'
/* Various PPP options */
ppp_opts= port speed 'mru' mru 'modem rtscts defaultroute priority 1 notify exit'
/* Bring it all together */
ppp_args= ppp_opts name_and_pwd 'connect' connect_string
/*
* Start PPP in another process and wait for connection ready
*/
start_opts= '/i /c /min' /* Inherit environment, use cmd.exe, background, minimized */
start_params= '"PPP ('connection')"' start_opts 'ducppp' connection ppp_args
/* Create named queue for lack of better IPC */
call RXQueue 'Create', connection'Queue'
/* Finally ready to run PPP */
say 'Starting: 'start_params
'@start 'start_params
/* Use connection queue */
default_queue= RXQueue( 'Set', connection'Queue' )
/* Wait for PPP to give its ready signal */
fExiting= 0
fConnected= 0
do while \fConnected
do QUEUED()
pull line
parse var line '['special']'
if special <> '' then do
if special = 'PPP' then do
call Time 'Reset' /* Start connection timer */
fConnected= 1
leave
end
else if special = 'ENDED' then do
if fExiting then
call Abort 'PPP Driver Ended Prematurely (No Connection Established)'
else
call Abort 'PPP Driver Failure'
end
else
say '['special']'
end
else if Pos( PPP_EXITING, line ) <> 0 then
fExiting= 1
else
say line
end
call SysSleep 1
end
/*
* We are connected!
*/
say "PPP Connection Established."
/* Switch to connected icon */
call SetObjectIcon CONNECTED, fBeep
/*
* Start any application passed
*/
if runthis <> '' then do
say 'Starting: 'runthis
address CMD 'start' runthis
end
/*
* Run a low intensity loop checking for idle time
*/
check_time= 0
traffic_time= 0
noise_time= 0
last_bytesum= 0
step= SLOWSTEP
fDisconnected= 0
do while \fDisconnected
tcps_sndbyte= ''
tcps_rcvbyte= ''
this_bytesum= ''
do QUEUED() /* Deplete queue if any */
pull line
parse var line '['special']'
if special <> '' then do
if special = 'ENDED' then do
fDisconnected= 1
leave
end
else
say '['special']'
end
else if this_bytesum = '' then do
if tcps_sndbyte = '' then
parse var line . "DATA BYTES SENT "tcps_sndbyte
else if tcps_rcvbyte = '' then
parse var line . "BYTES RECEIVED IN SEQUENCE "tcps_rcvbyte
else
this_bytesum= tcps_sndbyte + tcps_rcvbyte
end
end
if idle_timeout > 0 then do
this_time= Time('Elapsed')
if ( this_time - check_time ) > step then do /* Time to check traffic */
if this_bytesum = '' then do /* Need traffic data */
'@netstat -tcp | RXQueue' connection'Queue'
iterate
end
check_time= this_time
if this_bytesum <> last_bytesum then do /* We have had some traffic */
if step = QUICKSTEP then do /* We have come around */
step= SLOWSTEP
call SetObjectIcon CONNECTED
say 'Waking up with' this_bytesum 'bytes in traffic.'
end
traffic_time= this_time
last_bytesum= this_bytesum
end
else do /* No traffic since last time */
idle_time= this_time - traffic_time
if step = SLOWSTEP then do /* We have just fallen asleep */
step= QUICKSTEP
call SetObjectIcon SLEEPING
say 'Falling asleep after' this_bytesum 'bytes in traffic.'
end
else if idle_time > idle_timeout then do /* We have been idle too long time */
say 'Killing connection due to inactivity.'
call SetObjectIcon RUNNING
'@pppkill ppp0'
leave
end
else do /* No change of state */
if ( this_time - noise_time ) > NOISESTEP then do /* Just noise */
noise_time= this_time
if ( idle_time + ( NOISESTEP * 3 ) ) > idle_timeout then do
say 'Warning: Close to killing connection due to inactivity ('Trunc(idle_timeout-idle_time)' seconds remaining).'
call Beep 1440, 180; call Beep 1440, 180; call Beep 1440, 180
end
else if fBeep <> '' then /* Still sleeping */
call Beep 45, 270
end
end
end
end
end
call SysSleep 1
end
/*
* Connection ended without error
*/
connected_time= Trunc(Time('Elapsed')) /* Whole seconds only */
say 'PPP Connection Ended (Time online 'connected_time' seconds).'
/* Restore object to disconnected state and update total connect time */
say 'Restoring icon and state to disconnected...'
if SetObjectIcon( DISCONNECTED, fBeep ) then do
if connected_time <> '' then do
/* Update total connection time */
total_connect= STRIP( SysIni( inif, connection, 'TOTAL_CONNECT' ), 'both', D2C(0) )
if \DataType( total_connect, 'N') | \DataType( connected_time, 'N') then do
say 'Not valid numbers: 'total_connect', 'connect_seconds
return connected_time
end
total_connect= total_connect + connected_time
if 'ERROR:' = SysIni( inif, connection, 'TOTAL_CONNECT', total_connect ) then do
say 'Error writing INI file ('inif').'
return total_connect
end
end
say 'Icon and state restored OK.'
end
/* Remove resolv file */
'@erase' value(etc,,"OS2ENVIRONMENT")'\resolv'
/*
* We are done -> Clean up
*/
Terminate:
/* Delete named queue */
call RXQueue 'Delete', connection'Queue'
exit rc
/* ---------------------------
* Subroutines (fully exposed)
*/
Create:
/*
Create PPP connection objects on desktop.
To specify custom icons order is important ... stop, caution, go
Returns 1 on success, and 0 otherwise.
*/
parse arg dialupico progressico hangupico sleepico params
/* If custom icons ALL must be set or defaults will be used */
if dialupico = '' | progressico = '' | hangupico = '' then do
dialupico= DIALUPICON
progressico= PROGRESSICON
hangupico= HANGUPICON
end
if sleepico = '' then
sleepico= hangupico
/*
* Write icon names and initial state out to TCPOS2 for account
*/
fComplete= 0
if "ERROR:" = SysIni(inif,connection,DISCONNECTED,dialupico) then
say "Error INI write disconnected icon"
else
if "ERROR:" = SysIni(inif,connection,RUNNING,progressico) then
say "Error INI write running icon"
else
if "ERROR:" = SysIni(inif,connection,CONNECTED,hangupico) then
say "Error INI write connected icon"
else
if "ERROR:" = SysIni(inif,connection,SLEEPING,sleepico) then
say "Error INI write sleeping icon"
else
fComplete= 1
if \fComplete then do
say "Error writing to ini file."
return 0
end
/*
* Create connection object on desktop
*/
/* Executable settings */
setup= 'EXENAME='cmdpath'\duc.cmd;PARAMETERS='params '%'
/* Object settings (window) */
setup= setup || ';MINIMIZED=YES;CCVIEW=NO'
result= SysCreateObject('WPProgram',connection,'<WP_DESKTOP>','OBJECTID=<'Substr(connection,1,8,"_")'>;'setup,'R')
if result then do
call SetObjectIcon DISCONNECTED
say connection 'object created on desktop (move as you see fit).'
end
else
say "Difficulty creating" connection "object on desktop."
return result
Abort:
/*
Abnormal condition, indicate error, restore object icon and terminate!
*/
parse arg string
if string <> '' then
say string'.'
call Beep 999, 450
call SurfaceObject
say 'Press ENTER to exit.'
call Charin
call SetObjectIcon DISCONNECTED
rc= RC_ABORT
call Terminate
Halt:
/*
Handler for external attempts to interrupt and end execution.
Kill started processes, restore object and terminate.
*/
say 'Halting...'
/* Use default queue (if queue changed earlier) */
if Symbol( 'default_queue' ) = 'VAR' then
call RXQueue 'Set', default_queue
/* Kill dial command if running */
pid= GetProcessId(DIALCMD)
if pid <> 0 then do /* Dial command is running */
say DIALCMD "is running -> Killing its process!"
'@kill' pid
call SysSleep 1 /* Give PPP a chance to terminate itself */
end
/* Kill PPP if still running */
pid= GetProcessId(PPP)
if pid <> 0 then do /* Dial command is running */
say "PPP is running -> Killing its process!"
'@kill' pid
end
/* Restore object */
call SetObjectIcon DISCONNECTED, fBeep
say 'Halted.'
rc= RC_HALT
call Terminate
SetObjectIcon:
/*
Sets the icon of the current connection object.
Takes state and beeps on steady states if flagged.
Returns 1 if icon has been set, and 0 otherwise.
*/
arg state, fBeepFlag
iconfile= cmdpath'\'SysIni( inif, connection, state )
if "ERROR:" = iconfile then return 0
if SysSetObjectData( '<'Substr(connection,1,8,'_')'>', "ICONFILE="iconfile ) then do
call SysIni inif, connection, 'STATE', state
if state = CONNECTED then do
call SetObjectCCView 'Yes'
if fBeepFlag <> '' then call Beep 1440, 180
end
else if state = DISCONNECTED then do
call SetObjectCCView 'No'
if fBeepFlag <> '' then call Beep 900, 270
end
return 1
end
else
return 0
SetObjectCCView:
/*
Sets the CCView setting of the current connection object.
Takes 'Yes' or 'No' for setting (case does not matter).
Returns 1 if setting has been set, and 0 otherwise.
*/
arg setting
if SysSetObjectData( '<'Substr(connection,1,8,'_')'>', "CCVIEW="setting ) then
return 1
else
return 0
SurfaceObject:
/*
Surfaces existing window of the current connection object.
Returns 1 if setting has been set, and 0 otherwise.
*/
arg setting
if SysOpenObject( '<'Substr(connection,1,8,'_')'>', "DEFAULT", "TRUE" ) then
return 1
else
return 0
/* ----------
* Procedures
*/
TcpChk: PROCEDURE
/*
Checks that passed account exists and is valid.
Returns INI file if OK, otherwise the empty string is returned.
*/
Parse Arg account .
/* Look for TCPOS2.INI file */
inif= SysSearchPath("ETC", "tcpos2.ini")
if inif = '' then do
say "TCPOS2.INI file not found, perhaps TCP/IP is not installed."
return ""
end
/* This account found in TCPOS2.INI? */
type= SysIni(inif, account, 'SERVICE') /* test INI for account */
if type = 'ERROR:' then do
say "Create" account "in Dial Other Internet Providers, account not found."
return ""
end
type= DELSTR(type, LENGTH(type))
/* Service set for SLIP or PPP (must be the latter)? */
if type <> 'PPP' then do
say "Check" account "in Dial Other Internet Providers, not a PPP account!"
return ""
end
return inif
GetProcessId: PROCEDURE
/*
Returns process id (in decimal format) of executable given without extension.
*/
arg exesought
'@pstat /c | RXQueue'
do QUEUED()
pull pid . . exefound'.EXE' something
if ( something <> '' ) & ( Pos( exesought, exefound ) <> 0 ) then
return X2D(pid)
end
return 0