#!/opt/local/bin/kermit +
# Change the first line to the actual C-Kermit pathname on your computer.
#
.version = 1.01
# Fri Nov 16 15:58:31 2007
#
# Frank da Cruz CUIT
#
# Based on fac.ksc, see notes in that script.
#
# This one gets a full extensions report from the CBX and extracts the
# extension number and name into the result file, one record per line:
#
# nnnnn:text (5-digit exension number, colon, name if any).
#
# Result file is exten.cap
# Timestamped history log is exten.log
#
# Records are skipped if they don't have an extension number or if
# they don't match the record structure, e.g. in case of data loss.

#########################################
# DEFINITIONS AND SETTINGS...
# The first group can be overridden on the command line.

if not def production .production = 1   # 1 for production runs
if not def quiet .quiet = 1             # 1 for silent running as in cron
if not def debug .debug = 0             # 1 for verbose debugging
if not def timeout .timeout = 20        # Time (sec) to wait for data line
if not def test {                       # A test run (subset of records)
    .test = 0
    if equ "\v(user)" "fdc" .test = 1
}
if equ "\v(user)" "fdc" {               # Directory and file names
    .windowsdir := /tmp
    .unixdir := ~/logs
} else {
     # (Use forward slash in Kermit 95 for Windows directory separator)
    .windowsdir := L:/apps/Capture
    .unixdir := /src/network/scripts/pbx/logs
}
.logfile := exten.cap                   # Logfile name
.historyfile := exten.log               # History log

#########################################
# The rest of the script should not need changes.

.records = 0                            # Records seen
.skipped = 0                            # Records skipped
.count = 0                              # Records kept
.command = "LIST EXTEN ALL"             # Command for switch
undef \%w                               # Capture file channel number

if \m(quiet) {                          # Be quiet?
    set quiet on                        # Be quiet
    set input echo off                  # Be quiet
    set take echo off                   # Be quiet
} else {                                # Not quiet...
    set input echo on                   # Watch all dialogs
}
if \m(debug) {                          # Only for Frank
    set take echo on                    # Print each command upon execution
    set macro echo on                   # Print each command upon execution
}
if \m(test) {                           # Only for Frank
    set input echo on                   # Watch input
    .command = "LIST EXTEN (10000..11399)" # Get a briefer report
}
set exit warning off                    # Don't hassle me if I try to exit

# Macro to make a timestamped entry in the history log
define logentry {
    fwrite /line \%c "\v(timestamp): \%1"
    if fail fatal "History log write error - \f_errmsg()"
}

# Macro to handle fatal errors (C-Kermit should exit, K95 should not)
define fatal {
    if \f_status(\%c) logentry "FATAL - \%1" # First log the error
    if eq "\v(system)" "win32" stop 1 \%1 # so we can see the error message
    writeln error \10\v(cmdfile): FATAL - \%1 # Unix - write message to stderr
    exit 1                              # and exit with failure code
}

define on_exit {                        # Executed automatically on exit
    undef on_exit                       # Prevent recursion
    if \m(debug) {                      # Close any debugging logs
        if open session close session
        if open debug close debug
    }
    logentry "END SCRIPT status=\m(rc)" # Make final log entry
    fclose \%c                          # Close log
    if def \%w if \f_status(\%w) fclose \%w # Close capture file if open
}

# Macro to read a line from the input stream
define getline {
    clear input                         # Clear INPUT buffer from last time
    minput \m(timeout) {\13\10} {COMMAND: \29} # Data line or command prompt
    switch \v(instatus) {               # Handle MINPUT result
      :0                                # Success
        if == \v(minput) 2 goto done    # Check for prompt
        .s := \ftrim(\v(input))         # Trim CRLF and trailing whitespace
        end 0                           # and return
      :1                                # Timeout
        fatal "INPUT TIMEOUT \v(inwait) SEC"
      :2                                # User interruption
        stop 1 "INPUT INTERRUPTED FROM KEYBOARD"
      :4                                # I/O error
        fatal "CONNECTION LOST"
      :default                          # Other (unlikely)
        fatal "INPUT ERROR STATUS=\v(instatus)"        
    }
}

# Macro to skip a record
define skiprecord {
    increment skipped
    logentry "SKIP RECORD [\%1] \m(record): [\m(s)]"
    continue
}
# Execution starts here

.rc = 1                                 # Default exit status code is failure

switch \v(system) {                     # Choose appropriate logfile directory
    :win32
      .logs := \m(windowsdir)
      break
    :unix
      .logs := \m(unixdir)
      break
    :default
      echo WARNING: This script has not been tested on \v(system)...
      .logs := .            
}
if not directory \m(logs) {             # If it doesn't exist create it.
    mkdir \m(logs)
    if fail fatal "Can't create logfile directory - \m(logs)"
}
cd \m(logs)                             # Change to it.
if fail fatal "Can't CD to logfile directory - \m(logs)"

fopen /append \%c \m(historyfile)       # Open history file
if fail fatal "History log open error - \f_errmsg()"
logentry "BEGIN SCRIPT \v(cmdfile) v\m(version)"
if \m(production) logentry "COMMAND: \m(command)"

if exist \m(logfile) {                  # Check in advance before logging in
    if not writeable \m(logfile) fatal "Capture file \m(logfile) not writeable"
}

# Make the connection and log in

if \m(debug) {                          # But first... If debugging
    log session                         # Create a session log (very big)
    log debug                           # Create a debug log (huge)
}

set host 128.59.27.13 telnet
if fail stop 1 "Telnet connection failed"

for \%i 1 5 1 {                         # Try up to 5 times to get login prompt
   input \%i Login:                     # Use loop index for increasing timeout
   if success break                     # Got it - break from loop
    output \13                          # Send carriage return to wake it up
}
if > \%i 5 fatal "Timed out waiting for Login prompt"

lineout steve                           # Send user ID
input 10 "password: "                   # Wait up to 10 sec for Password prompt
if fail fatal "Timed out waiting for password prompt"
lineout "stevenjo "                     # Send password
input 10 "Selection > "                 # Wait up to 10 sec for menu prompt
if fail fatal "Timed out waiting for Selection > prompt"
msleep 500                              # Wait 500 msec then send response

# From here we have to avoid Telnet NVT mode (CR -> CRLF)
# And in many cases we have to terminate commands with LF (\10)
# rather than CR (\13).

set telnet newline binary               # This disables NVT mode
output 1\10                             # Digiboard login
minput 20 "Cannot open this port or hunt group." "Digi Username:"
if fail fatal "Timed out waiting for Digi prompt"
if == \v(minput) 1 fatal "Digi port not available"

set input timeout quit                  # 
msleep 100
output "steve\10"
input 10 "Digi Password:"
msleep 100
output "stevenjo \10"

# Once we get to the switch console it can be in any of five states,
# depending on how it was left last time.  The following code should
# allow for all possibilities.

set input timeout proceed               # So we can test MINPUT result
for \%i 1 8 1 {                         # Try this up to 8 times
    minput 3 "COMMAND: " "USERNAME: " "PASSWORD: " "1% \29" "% \29" 
    switch \v(minput) {
      :1, forward SKIPAHEAD
      :2, msleep 100, output netdev\10, break 
      :3, msleep 100, output g0td4t4\10, break 
      :4, msleep 100, output cn\10, break
      :5, msleep 100, output logon node 1\10, break
      :default, output \10
    }
}
fatal "Failure to get CBX Console login prompt"  # Loop count exhausted

:SKIPAHEAD

# At this point we should have the COMMAND prompt

set input timeout proceed
if \m(production) {                     # If it's a production run
    if exist \m(logfile) {              # Delete previous logfile
        logentry "DELETE \m(logfile) \fsize(\m(logfile)) \fdate(\m(logfile))"
        delete \m(logfile)              # (Or rename it for backup)
    } else {
        logentry "DELETE (no previous logfile found)"
    }
    logentry "BEGIN CAPTURE \m(logfile)"
    fopen /write \%w \m(logfile)        # Start a new logfile.
    msleep 100                          # A short pause just in case.
    output "\m(command)\10"             # Start the report - takes about 3 hrs

    while true {                        # Loop for all incoming records
        getline                         # Look for EXTN tag
        if not eq {\s(s[1:7])} {   EXTN} continue
        increment records               # Have a new record
        getline                         # Skip dashed line
        if not eq {\s(s[1:7])} {   ----} skiprecord A
        getline                         # Get extension
        if not match \s(s[1:9]) DS\32[0-9][0-9][0-9][0-9][0-9]\32 skiprecord B
        .number := \s(s[4:5])
        getline                         # Skip two lines
        getline
        getline                         # Get NAME tag
        if not eq {\s(s[1:11])} {   ACD NAME} skiprecord C
        getline                         # Skip dashed line
        if not eq {\s(s[8:15])} {---------------} skiprecord D
        getline                         # Get name
        if not eq {\s(s[1:2])} {DS} skiprecord E
        .name := \ftrim(\s(s[8:]))
        increment count                 # Count good record
        fwrite /line \%w \m(number):\m(name) # Write extension and name
    }
}
:DONE                                   # Come here from getline

if \m(production) {                     # If it's a production run
    fclose \%w                          # Close logfile
    logentry -                          # and make log entry
      "END CAPTURE \m(logfile) size=\fsize(\m(logfile)) records=\m(count)"
    logentry "STATUS: SUCCESS"
}

# Now exit the CBX console, the Digi, and the Telnet host.  If any of the
# following INPUTs fails we just exit, which closes the Telnet connection
# automatically, which presumably should also shut the others but who knows.
# Exit status is success even if any of the following fails because we
# already captured the log.

.rc = 0                                 # Exit status is success

set input timeout quit
output "bye\10"
input 20 "1% \29"
msleep 100
output "bye\10"
input 20 "% \29"
msleep 100
output "bye\10"
output \10
minput 20 "USERNAME" "PASSWORD"
output "&\10"
input 20 "Selection > "
lineout "0\10"
input 2 \10
sleep 1
exit \m(rc)
