#!/usr/local/bin/kermit +
#
# Modem test script.
# Runs on UNIX, VMS, and Windows 95/98/NT/2000.
# Requires C-Kermit 7.0 or K95 1.1.18 or later.
#
# Dials two (or more) different modem pools repeatedly.
# Logs connection & performance statistics for comparison in modem.log file.
# Connection statistics are supported for USR and Compaq modems.
# Performance stats come from up- and downloading a file of your choice.
#
# The script runs forever, with a chance to exit at the end of each trip
# through the loop ("Press any key within 5 seconds").
#
# In UNIX only, give this script execute permission and make sure the top
# line points at the C-Kermit 7.0 Beta.06 (or later) executable, and then 
# you can run it just like a shell script, in which case it accepts the
# following optional command-line arguments:
#
#  1. hostname
#  2. username on host
#  3. name of local file to up- and download
#
# For example: "modemtest somehost.columbia.edu olaf test.zip"
#
# If these are not supplied the script prompts for them.
# You are prompted for the password in any case.
#
# Other parameters can be passed as environment variables:
#
#  DEVICE - Name of dialout device
#  MODEM  - A C-Kermit/K95 "set modem type" keyword
#  SPEED  - Serial port speed (default 115200)
#
# The default device for UNIX is /dev/cua and for Win95/98/NT it's TAPI.
# The default modem type for UNIX is USROBOTICS.
#
# Author: F. da Cruz, Columbia University, 30 Apr 1999
#
# Modified 19 May 1999
#  . New USRSTATS macro illustrates a cleaner report-parsing method.
#  . New SET BELL OFF command added for silence.

define badversion echo C-Kermit 7.0 or K95 1.1.18 Beta.06 required, exit
if LLT \v(version) 70000 badversion

local origin model firmware \&n[] \%i \%j \%n 
local debug retrains blers ispeed ospeed
local user pass host file upcps dncps head

; Configuration parameters -- change as needed (*)

.origin = 212-555-1234                   ; (*) Phone number you're calling from
dcl \&n[] = 555-7654 555-9876            ; (*) Replace by real phone numbers
dcl \&p[4] = abc xyz                     ; (*) Up to 4 possible prompt roots
.\%n := \fdimension(&n)                  ; Number of numbers

.debug = 1                               ; (*) Change to 0 for minimal messages
.logfile = modem.log                     ; (*) Log file name

; Device, modem, and speed -- Environment variables override defaults...

if not def device .device := \$(DEVICE)  ; Dialout device / port
if not def modem  .modem  := \$(MODEM)   ; Type of modem on port
if not def speed  .speed  := \$(SPEED)   ; Serial port speed

switch \v(system) {                      ; Device and modem defaults...
  :win32                                 ; For Windows 95/98/NT/2000
    if not def device .device = tapi     ; (*) Change if necessary
    if not def modem .modem = tapi       ; (*) Ditto
    if not def speed .speed = 115200     ; (*) Port speed - change if necessary
    break
  :unix                                  ; For UNIX...
    if not def device .device = /dev/cua ; (*) Change to your dialout device
    if not def modem .modem = usrobotics ; (*) Change to match your modem
    if not def speed .speed = 115200     ; (*) Port speed - change if necessary
    break
  :vms                                   ; For VMS...
    if not def device .device = TTA0:    ; (*) Change to your dialout device
    if not def modem .modem = usrobotics ; (*) Change to match your modem
    if not def speed .speed = 57600      ; (*) Port speed - change if necessary
    break
  :default
    ; Add others here...
    exit 1 Sorry - this script does not run on \v(platform).
}

.model = UNKNOWN                    ; Modem model
.firmware = UNKNOWN                 ; Modem firmware

if def \%1 .host := \%1             ; Accept host, user, and filename
if def \%2 .user := \%2             ; from command line (UNIX only)
if def \%3 .file := \%3             ; or from TAKE command line.

; Macro definitions

def usrinfo {                       ; Get info about USR modem
    ; If we weren't cheating we'd do ATI6 and parse the results.
    ; See usrgetstats for a non-cheating example.
    ; Meanwhile change the strings to match your own modem.
    .model = USRobotics Courier V.32bis V.34+ Fax
    .firmware = 6.2.3 / 1.2.4
}

def cpqinfo {                       ; Get info about Compaq modem
    ; If we weren't cheating we'd do ATI and parse the results.
    ; See cpqgetstats for a non-cheating example.
    ; Meanwhile change the strings to match your own modem.
    .model = Compaq Presario 56K-DF
    .firmware = 1.3.12
}

def getmdminfo {                    ; Get modem info.
    switch \v(modem) {
      :usrobotics
         usrinfo, break
      :tapi
      :compaq
         cpqinfo, break
    }
}

; Get and parse a statistics report from a USR modem.
; This version parses the report on the fly.

def usrstats {                      ; Get USR connection statistics.
    local \%x \%y \%z
    clear input
    output ATI6\13                  ; Send ATI6 and parse output.
    set flag off
    set input echo on
    while not flag {
       minput 10  Blers  Retrains  Speed  OK
       switch \v(minput) {
	 :1, clear input, input 2 \10, .blers := \fword(\v(input),1), break
	 :2, clear input, input 2 \10, .retrains := \fword(\v(input),5), break
	 :3, clear input, input 2 \10, .ospeed := \fword(\v(input),1,,/), break
	 :4, set flag on, break
       }
    }
}

; Get and parse a statistics report from a USR modem.
; This version (which works but is not used) reads the whole report at
; once and parses it afterwards.  The Compaq report parser (next macro)
; also uses this method.

def xusrstats {                     ; Get USR connection statistics.
    local \%x \%y \%z
    clear input
    output ATI6\13                  ; Send ATI6 and parse output.
    input 20 OK		  
    if fail end 1
    .\%x := \findex(Retrains Granted,\v(input))
    if \%x .retrains := \fword(\fsubstr(\v(input),\%x),3)
    .\%x := \findex(Blers,\v(input),\%x+16)
    if \%x .blers := \fword(\fsubstr(\v(input),\%x),2)
    .\%x := \findex(Speed,\v(input),\%x+16)
    if \%x .ospeed := \fword(\fsubstr(\v(input),\%x),2,,/)
}

; Get and parse a statistics report from a Compaq modem.
; This version reads the whole report at once and parses it afterwards.

def cpqstats {                      ; Get Compaq connection statistics.
    local \%x \%y \%z
    clear input
    output ATI11\13                 ; Send ATI11 and parse output.
    pause 2
    out \32                         ; Tickle "press any key to continue"
    input 20 OK		  
    if fail end 1
    .\%x := \findex(Final   Transmit Carrier Rate,\v(input))
    if \%x .\%y := \fword(\fsubstr(\v(input),\%x),5)
    .\%x := \findex(Final   Receive  Carrier Rate,\v(input))
    if \%x .\%z := \fword(\fsubstr(\v(input),\%x),5)
    if \%x .ospeed := \%y/\%z    
    .\%x := \findex(Receive  Frame Error Count,\v(input))
    if \%x .blers := \fword(\fsubstr(\v(input),\%x),5)
    .\%x := \findex(Retrain by Local  Modem,\v(input))
    if \%x .retrains := \fword(\fsubstr(\v(input),\%x),5)
}
def getmdmstats {                   ; Get modem connection statistics.
    switch \v(modem) {
      :usrobotics
         usrstats, break
      :tapi
      :compaq
         cpqstats, break
    }
}
def openlog {                       ; Open the log file and write heading
    open append \m(logfile)
    if fail exit 1 Can't open log "\m(logfile)"
    writeln file
    writeln file {Time:            \v(date) \v(time)}
    writeln file {Platform:        \v(platform)}
    writeln file {Modem:           \m(model)}
    writeln file {Firmware:        \m(firmware)}
    writeln file {Interface Speed: \m(speed)}
    writeln file {Calling from:    \m(origin)}
    writeln file {Log File:        \m(logfile)}
    writeln file {Test File:       \m(file)}
    writeln file {Test File Size:  \fsize(\m(file))}
    writeln file
    write file   {Date  Time  Number    Speed  Speed-After    }
    writeln file {Blers Retrains   Upload   Download}
    write file   {----------  --------- -----  -----------    }
    writeln file {----- --------  -------   --------}
}
def flushlog {
    close write
    open append \m(logfile)
    if fail exit 1 Can't reopen log "\m(logfile)"
}
define logrecord { writeln file {\m(head)  \%1} } ; Write a log entry

define dologin {                     ; Login from terminal server to host
    output telnet \m(host)\13        ; and start Kermit in server mode there.
    input 30 login:
    if fail end 1
    out \m(user)\13
    input 10 Password:
    if fail end 1    
    out \m(pass)\13
    input 60 {$ }
    output kermit -x\13
    input 20 READY TO SERVE...
    if fail end 1
}
def doio {                           ; Transfer a file back & forth 
    set file collision overwrite     ; and get performance statistics
    while exist \m(file) {
        remote cd /tmp
        if fail break
        remote set file collision overwrite
        if eq \v(system) UNIX set wild kermit ; (bug - fix later)
	send \m(file) delete.me
	if fail break
	.upcps := \v(cps)
	get delete.me
	if success .dncps := \v(cps)
        break
    }
    bye
}

; End of macro definitions

while not def host {                 ; Get hostname 
    ask host { Host: }               ; if not given on command line...
}
while not def user {                 ; Ditto for username...
    ask user { User: }
}
while not def pass {                 ; Always prompt for password.
    askq pass { Password: }
}
while not def file {                 ; Get filename if not given 
    ask file { File to transfer: }   ; on command line.
    if exist \m(file) break
    echo \m(file) not found.
}
if not equal "\m(device)" "tapi" {   ; Except in K95...
    set modem type \m(modem)         ; Specify modem type
    if fail {                        ; Check for error
        exit 1 {Error: Modem type "\m(modem)" not known}
    }
}
set carrier off                      ; Don't require carrier
set line \m(device)                  ; Open the device
if fail {                            ; Check for failure
    exit 1 {Error: \m(device) not available}
}
set speed \m(speed)                  ; Set the desired speed

getmdminfo                           ; Get modem info
set xfer bell off                    ; Turn off annoying bell

if \m(debug) {                       ; Echo parameters for this run...
    echo { Device:      \m(device)}
    echo { Speed:       \m(speed)}
    echo { Modem:       \m(modem)}
    echo { Model:       \m(model)}
    echo { Firmware:    \m(firmware)}
    echo { Host:        \m(host)}
    echo { User:        \m(user)}
    echo { Password:    \frepeat(*,\flen(\m(pass)))}
    echo { File:        \m(file)}
    echo { Size:        \fsize(\m(file))}
    set modem speaker on
    set dial display on
    set input echo on
    set xfer display full
} else {
    set modem speaker off
    set dial display off
    set input echo off
    set quiet on
    set xfer display brief
}

; Line is open...

set dial retries 0                   ; No redialing
set dial speed-matching off          ; No speed changing
def on_exit hangup                   ; In case of Ctrl-C
set exit warning off                 ; In case of misconfigured modem
set bell off                         ; Silence please
if \m(debug) show comm

openlog                              ; Start logging

while true {                         ; Loop till user types something
    for \%i 1 \%n 1 {
        .\%9 := \fcvtdate(\v(date) \v(time))
        .date := \fsubstr(\%9,5,2)/\fsubstr(\%9,7,2)
        .time := \fsubstr(\%9,10,2)\fsubstr(\%9,13,2)
        .head := \m(date) \m(time)  \&n[\%i]
        .upcps = FAILED
        .dncps = FAILED
        clear dial-status
        dial \&n[\%i]
        if fail {
            switch \v(dialstatus) {
              :8, logrecord {FAILED: Timed out}, break
              :9, logrecord {FAILED: User canceled}, exit 0
              :10, logrecord {FAILED: Modem not ready}, break
              :default, logrecord {FAILED: "\v(dialresult)"}, break
            }
            continue
        }
        .ispeed := \fword(\v(dialresult),2)

        for \%j 1 10 1 {             ; Get terminal server prompt
            output \13
            minput 10 \&p[1] \&p[2]
            if success break
        }
        if = \%i 10 {
	    logrecord {FAILED: No terminal server prompt}
	    continue
        }
        input 2 >                    ; Do some i/o...
        if success { 
             dologin
             if success doio            
        }
        output \13                   ; Log out from terminal server
        minput 10 \&p[1] \&p[2]
        if success {
            input 2 >
	    if success {
		output exit\13
		input 20 NO CARRIER
		if fail hangup
		pause 1
	    }
        }
        .retrains = UNKNOWN
        .blers = UNKNOWN    
        .ospeed = UNKNOWN
        output AT\13                 ; Make sure we're in command mode.
        input 3 OK
	if success {                 ; We are - Get statistics from modem.
            getmdmstats
	    .\%7 := \flpad(\m(ispeed),5)\flpad(\m(ospeed),13)
	    .\%8 := \flpad(\m(blers),7) \flpad(\m(retrains),8)
	    .\%9 := \flpad(\m(upcps),9) \flpad(\m(dncps),10)
	    logrec {\%7 \%8 \%9}     ; Write log record
        }
	set ask-timer 5
        getc \%j {Press any key within 5 seconds to quit: }
        if not asktimeout exit
        set ask-timer 0
        echo Continuing...
    }
}
exit
