#!/usr/local/bin/kermit8
; --------------------------------------------------------------------
;
; cook2.ksc
;
;
; Author
; ------
; R. M. Almeria, Anteon Corp., 2003
;
;
; Purpose
; -------
; This kermit script is designed to take 1 to N times two arguments 
; (a pager-id and a message) and to connect to Arch's paging service 
; via a modem using their special service number.
;
; So you can basically connect to the service and issue several pages 
; or just one.  You could send a message to someone's pager like so:
;
;	cook2.ksc 4441111 "hello world"
;
; or you could send multiple messages to multiple pagers like so:
;
;	cook2.ksc 4441111 "test1" 4442222 "test2" 4443333 "test3"
;
;
; Special Remarks
; ---------------
; This program implements the TAP (Telocator Alphanumeric Protocol)
; for pagers.
;
;
; Language
; --------
; This program is written in Kermit script.  Please read the book
; "Using C-KERMIT" by Frank da Cruz et al., for more details.
; 
;
; Revision History
; ----------------
; v1.1 -- February 5, 2003 @ 3:48 PM 
;	Added copious debug statements that are toggled (0/1) via
;	the DEBUG constant (it is defined in the initialization section).
;
; v1.0 -- January 28, 2003 @ 5:55 PM 
;	Initial revision.
;
; --------------------------------------------------------------------

; --------------------------------------------------------------------
; Check the number of command line arguments and exit if insufficient. 
; --------------------------------------------------------------------
  xif < \v(args) 4 {
    echo \10This kermit8 paging script accepts unlimited alphanumeric-
 pager-id/message pairs.\10
    echo {SYNTAX:\10\9cook2.ksc pagerid1 message1 pagerid2 message2-
 pagerid3 message3 . . . \10}
    echo {    EX:\10\9./cook2.ksc 9992322 "Hello World!"\10}
    exit
  }

; --------------------------------------------------------------------
; Define the SendBlock function which sends a message (block) to the
; paging service.  This function is also called initially to send the
; first message.
; --------------------------------------------------------------------
def SENDBLOCK {
  local \%b \%c \%s blk

  ; Create a string composed of the pager-id and message with
  ; appropriate control chars.
  assign \%b \2\&p[\%m]\13\&m[\%m]\13\3

  ; Calculate the checksum required for TAP and add to the final
  ; message string that will be sent to the paging service.
  assign \%c \fchecksum(\%b)
  assign blk \%b\fchar(\fmod(\%c/256,16)+48)\fchar(\fmod(\%c/16,16)+48)\fchar(\fmod(\%c,16)+48)\13

  assign \%s \flength(blk)

  ; Make sure that the size of the block is less than MaxBlockSize.
  xif < \%s \%y {
    if \m(DEBUG) echo {DEBUG: {SENDBLOCK}  Sending '\&m[\%m]' to '\&p[\%m]'}
    output \m(blk)
    return 1 
  } else {
    return 0
  }

}

; --------------------------------------------------------------------
; Define the SendNextBlock function which sends the second thru last 
; messages (blocks) to the paging service (one block sent per 
; function call).  This function calls SendBlock to send its messages.
; --------------------------------------------------------------------
def SENDNEXTBLOCK {

  xif < \%m+1 \%n {

    ; There are still messages to send so send them.

    assign \%q 0	; Reset the retries counter.
    assign \%m \feval(\%m + 1)
   
    sendblock
    return \v(return)

  } else {

    ; We are done with the paging service so disconnect.

    output \4\13	; Send <EOT><CR>
    if \m(DEBUG) echo {DEBUG: {SENDNEXTBLOCK} Sending <EOT><CR>.}
    input 3 {\27\4\13}	; Look for <ESC><EOT><CR>
    assign \%f 1	; Set Finished to true.
    return 0
  }

}

; --------------------------------------------------------------------
; Define the TAP (Telocator Alphanumeric Protocol) function.
; --------------------------------------------------------------------
def SENDTAPMSG {

  assign \%o \6\13	; OK 		= <ACK><CR>
  assign \%t \21\13	; TRY AGAIN	= <NAK><CR>
  assign \%a \30\13	; ABANDON	= <RS><CR>
  assign \%d \27\4\13	; DISCONNECT	= <ESC><EOT><CR>
  
  assign \%x 0		; Initialize the loop variable.

  assign \%f 0		; Initialize Finished flag to false.
  assign \%w 5		; Initialize MaxIDAttempts.

:dowhile

  ; Look for 'ID=' string for at least MaxIDAttempts before exiting.
  xif = \%f 0 {
    xif < \%x \%w {
      output \13
      input 3 {ID=}
      xif success {
        assign \%f 1
      } else {
        assign \%x \feval(\%x + 1)
      }
      goto dowhile
    }
  } 

  ; Exit if we didn't get the 'ID=' string.
  xif = \%f 0 {
    assign \%e 0  
    end
  }

  assign \%q 0		; Initialize protocol Retries and NOT dialing retries.
  assign \%u 1		; Initialize First to true.
  assign \%f 0		; Reset Finished to false.
  assign \%v 0		; Initialize SentBlock to false.
  assign \%y 233	; Define MaxBlockSize.  Typically 256 according to the
			; protocol but Cook limits this to 233.
  assign \%z 3		; Define MaxRetries.

  while = \%f 0 {
    xif = \%u 1 {
      xif < \%q \%z {
        if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} Sending <ESC>PG1<CR>.}

	; Tell the paging service that we want to send an
        ; alphanumeric page.
        output {\27PG1\13}	; Sending <ESC>PG1<CR>    

        ; Wait for a response from the paging service...
        ; either OK, TRY AGAIN, DISCONNECT, 'ID=' or
        ; TIMEOUT.
        minput 3 {\%o} {\%t} {\%d} {ID=}

        switch \v(minput) {
          :0, break		; TIMEOUT 
          :1,                   ; OK         = <ACK><CR> 
              if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} Received OK.}
              if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} Waiting for <ESC>[p<CR>.}

              ; Wait for the go-ahead from the paging service.
              input 3 {\27[p\13}
              xif success {
                msleep 500
                xif < \%m \%n {
                  if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} Calling SENDBLOCK.}
                  sendblock	; Send first block.
                  assign \%v \v(return)
                  assign \%u 0
                } else {
                  assign \%f 1	; Set Finished to true.
                }
              } else {
                assign \%f 1	; Set Finished to true.
              }
              break		
          :2,                   ; TRY AGAIN  = <NAK><CR> 
              if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} Received TRY AGAIN.}
              break
          :3,                   ; DISCONNECT = <ESC><EOT><CR> 
              if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} Received DISCONNECT.}
              assign \%f 1	; Set Finished to true.
              break		
          :4, break		; Received 'ID=' send <ESC>PG1<CR> again
        }

        ; Increment the Retries counter.
        assign \%q \feval(\%q + 1)

      } else {
        assign \%f 1		; Set Finished to true.
      }
    } else {

      ; Look for the response to the first and succeeding blocks that
      ; were sent to the paging service.  We are waiting for an OK,
      ; ABANDON, TRY AGAIN, DISCONNECT or TIMEOUT response.
      minput 3 {\%o} {\%a} {\%t} {\%d}
      switch \v(minput) {
        :0, break		; TIMEOUT 
        :1,                     ; OK	     = <ACK><CR> 
            if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} - Received OK.}
            msleep 500   
            if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} - Calling SENDNEXTBLOCK.}
            sendnextblock
            assign \%v \v(return)
            break
        :2,                     ; ABANDON    = <RS><CR> 
            if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} - Received ABANDON.}
            msleep 500   
            if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} - Calling SENDNEXTBLOCK.}
            sendnextblock
            assign \%v \v(return)
            break
        :3,                     ; TRY AGAIN  = <NAK><CR>
            if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} - Received TRY AGAIN.}
            msleep 500
            xif = \%v 1 {
              xif < \%q \%z {
                sendblock
                assign \%v \v(return)

		; Increment the retries counter.
                assign \%q \feval(\%q + 1) 
              } else {
                sendnextblock
                assign \%v \v(return)
              }
            } else {
              sendnextblock
              assign \%v \v(return)
            }
            break
        :4,                     ; DISCONNECT = <ESC><EOT><CR>
            if \m(DEBUG) echo {DEBUG: {SENDTAPMSG} - Received DISCONNECT.}
            assign \%f 1	; Set Finished to true.
            break
      }
    }
  }
  
  xif < \%m+1 \%n {
    assign \%e 0		; Return false (Didn't send all messages due to errors).
  } else {
    assign \%e 1		; Return true (We sent all of the messages).
  }
}


; --------------------------------------------------------------------
; Initialization.
; --------------------------------------------------------------------

  assign DEBUG 1

  ; Calculate the number of messages to send.
  assign \%n \feval( (\v(args) - 2)/2)	

  declare \&p[\%n]		; Declare the pager-id array.
  declare \&m[\%n]		; Declare the message array.

  ; Populate the pager-id and message arrays with the args.
  for \%x 0 \%n-1 1 {
    assign \%i \feval(2 + (\%x * 2))	; Compute the pager-id index.
    assign \%j \feval(3 + (\%x * 2))	; Compute the message index.

    assign \&p[\%x] \&@[\%i]		; Add pager-id to pager-id array.
    assign \&m[\%x] \&@[\%j]		; Add message to message array.
  }

  assign \%m 0			; Initialize message index (MIndex).

  assign \%r 0			; Initialize the Reconnects counter.
  assign \%s 3			; Define MaxReconnects.

  assign COOKPDX 9,5031234567   ; Set to local paging service phone number.

  assign \%e 0			; Initialize TAP Error Flag to false.

; --------------------------------------------------------------------
; Try to connect to the paging service.
; --------------------------------------------------------------------
:restart

  if \m(DEBUG) echo {\10DEBUG: RESTART NO. \%r}
  set modem hangup-method modem-command 
  if \m(DEBUG) echo {DEBUG: Issuing initial HANGUP.}
  hangup

  if \m(DEBUG) echo {DEBUG: Setting modem type}
  set modem type att-dataport
  if \m(DEBUG) echo {DEBUG: Setting the port to '/dev/cua/4'}
  set port /dev/cua/4
  xif failure {
    echo {ERROR: I could not connect to /dev/cua/4}
    goto terminate 
  } 

  if \m(DEBUG) echo {DEBUG: Setting up the terminal.}
  set speed 2400
  set parity even
  set stop-bits 1
  set flow-control xon/xoff
  set modem flow none
  set modem error-correction off
  set modem data-compression off
  set modem speed-matching off
  ;set carrier-watch off
  set output pacing 200
  set dial retries 5
  set dial interval 1

  if \m(DEBUG) echo {DEBUG: DIALING....}
  dial \m(COOKPDX)
  xif success {
    if \m(DEBUG) echo {DEBUG: Calling SENDTAPMSG.}
    sendtapmsg
    xif = \%e 0 {
      xif < \%r \%s {
        xif < \%m \%n {
          assign \%r \feval(\%r + 1)
          goto restart
        }
      }
    } 
  }

:terminate

  if \m(DEBUG) echo {DEBUG: Hanging up.}
  hangup
  if \m(DEBUG) echo {DEBUG: Exiting.}
  exit
