*BSD News Article 17909


Return to BSD News archive

Path: sserve!newshost.anu.edu.au!munnari.oz.au!uunet!haven.umd.edu!cville-srv.wam.umd.edu!ni.umd.edu!sayshell.umd.edu!louie
From: louie@sayshell.umd.edu (Louis A. Mamakos)
Newsgroups: comp.unix.bsd
Subject: Re: BSDI and IXO
Date: 3 Jul 1993 15:21:53 GMT
Organization: University of Maryland, College Park
Lines: 290
Message-ID: <21486h$f5q@ni.umd.edu>
References: <20sp7v$9hr@cyberspace.com>
NNTP-Posting-Host: sayshell.umd.edu

In article <20sp7v$9hr@cyberspace.com> brc@cyberspace.com (Brian Cartmell) writes:
>Does anyone have a program that works on BSD that will connect to a device
>dial a number and transfer Alpha Pager Message via the IXO for alpha pagers?

I have an expect script (actually, two files) that does this.  It can
use tip(1) to actually talk to the modem.  We also have a different
module that telnets to an terminal server with dial-out modems too,
that just uses a different "hardware" file.

This pretty ugly and disgusting, but the implementation of the IXO
protocol in TCL, I thought, was rather interesting.

It's usually invoked as 

	beep pagerid "It's broken!  Help!"  pagerid2 "Help! It's down!"

there's also a way to pass it a file containing pagerids and messages for
"bulk" beeping.

Louis Mamakos


------------ beep.expect
#!/local/bin/expect
#
#  Call a beeper.  By default, uses tip(1c) to establish the modem connection
#  which requires an entry in /etc/remote that looks like this:
#
#    dialer:dv=/dev/cufa:br#38400:pa=even:
#

log_user 0
#debug 1

# definition of paging service's phone number
set service "474-4657"
# hardware to use
set hardware beep.tip

# definitions of various ascii control characters used by the paging
# protocol

set STX \002
set ETX \003
set ACK \006
set NAK \025
set RS  \036
set ESC \033
set EOT \004


# ===

proc error { msg } {
	puts stderr "Error: $msg"
	exit
}

# ===

#
#  compute the checksum over the paging transaction packet.  Return the
#  checksum string
#
proc checksum { s } {
	set sum 0
	foreach ch [split $s {}] {
		scan $ch "%c" v
		incr sum $v
	}
	return [format "%c%c%c" [expr "48 + (($sum >> 8) & 15)"] \
				[expr "48 + (($sum >> 4) & 15)"] \
				[expr "48 + ($sum & 15)"]];
}

# ===

proc get_response {} {
	global ACK NAK RS ESC EOT

	expect	"*$ACK\r"     {puts stderr "resp: OK";  return "OK"} \
		"*$NAK\r"     {puts stderr "resp: NAK"; return "NAK"} \
		"*$RS\r"      {puts stderr "resp: ABANDON"; return "ABANDON"} \
		"*$ESC$EOT\r" {puts stderr "resp: DISC"; return "DISC"} \
		timeout	      {puts stderr "resp: TIMEOUT"; return "TIMEOUT"}
}

# ===

#
#  Generate a page to "pin" carrying the message "message"
#
proc page { pin message } {
	global STX ETX

	set attempts 0

	regsub "\t+" $message " " message
	set message [string range $message 0 238]

	set pgstr "${STX}${pin}\r${message}\r${ETX}"
	set block "$pgstr[checksum $pgstr]\r"

	send $block
	puts stderr "Sending page to $pin"
	set resp [get_response]
	#
	#  Examine the response.  Only "NAK" responses are retried
	#
	while {! [string compare "NAK" $resp] && $attempts < 5} {
		puts stderr "Resending block due to NAK"
		exec sleep 1
		send $block
		set resp [get_response]
		incr attempts
	}
	return $resp
}

# ===

#
#  condition the paging system to accept the Paging Entry Terminal protocol,
#  rather than thinking we're a dumb terminal out here.
#
proc dologin {} {
   global ESC

   foreach i {once} {
	set timeout 5
	expect {*ID=} break	timeout {}
	set timeout 2
	send "\r"
	expect {*ID=} break	timeout {}
	send "\r"
	expect {*ID=} break	timeout {}
	send "\r"
	expect "*ID=" break	timeout {}
	send "\r"
	expect "*ID=" break	timeout {
		send_user "Error: waiting for id= prompt\r"
		return -1
	}
   }

   set timeout 10

   # this is the magic bit..
   send "${ESC}PG1000000\r"

   case [set resp [get_response]] in {
	OK	{puts stderr "Logged into paging service"}
	NAK   {error "to send of PG1"}
	TIMEOUT {error "timeout of response to PG1"}
	*	{error "Unexpected response '$resp' during login"}
   }
   return 0
}

# ===

proc logout {} {

	global EOT

	send "$EOT\r"
	case [get_response] in {
		DISC	{puts stderr "Normal disconnect"}
		RS	{puts stderr "Some pages may have failed"}
	}
}

# ============= start of main program =============


set argc [llength $argv]
set dofile 0

set arg 1

if {$argc>2 && ([string compare FILES [lindex $argv 1]] == 0)} {
	set dofile 1
	set arg 2
} else {
   if {$argc < 3} {
	puts stderr \
               "usage: [lindex $argv 0] pagerid message \[pagerid message ...\]"
	exit
    }
}

source $hardware

set success 0
for {set tries 5} {$tries} {set tries [expr $tries-1]} {
	# invoke communication facility specific function to establish
	# a connection with the paging service
	connect $service

	# attempt to initiate session protocol
	if {[dologin] == 0} {
		set success 1
		break
	}
}
if { $success == 0 } {
	error "Gave up looking for a working modem at the other end"
}

while {!$dofile && ($arg < $argc)} {
	set who [lindex $argv $arg]
	set msg [string range [lindex $argv [expr $arg+1]] 0 238]
	set arg [expr $arg+2]

	puts stderr "Paging $who with $msg"
	page $who "$msg"
}

if {$dofile} {
   while {$arg < $argc} {
	set dofile [open [set filename [lindex $argv $arg]] r]
	incr arg

	if {[gets $dofile who] < 0} {
		puts stderr "EOF reading recpient from $filename"
		exec rm -f $filename
		continue
	}

	if {[gets $dofile msg] < 0} {
		puts stderr "EOF reading message from $filename"
		exec rm -f $filename
		continue
	}

	if {[regsub "^ID=" $who "" who] == 0} {
		puts stderr "$filename: Missing ID= on pager line"
		exec rm -f $filename
		continue
	}
	if {[regsub "^MSG=" $msg "" msg] == 0} {
		puts stderr  "$filename: Missing ID= on pager line"
		exec rm -f $filename
		continue
	}
	close $dofile
	puts stderr "Paging $who with $msg"
	if {[page $who "$msg"] == "OK"} {
		exec rm -f $filename
	}
   }
}

# end session protocol
logout

#
# invoke communication facility specific function to disconnect from
# paging service
#
disconnect "Mission sucessful\n"
exit 0


----------- beep.tip

proc connect { pagerservice } {
   global spawn_id pid

   uplevel 1 set pid [spawn tip dialer]

   expect "connected*"

   send "AT\r"
   expect "*OK*" {}

   send "ATE0\r"
   expect "*OK*" {}

   send "ATM0&N15&K0DT${pagerservice}\r"
   set timeout 20
   expect "*CONNECT*\r" {}  timeout {error "modem didn't return CONNECT"}
   expect_after 	eof	{error "Got EOF (default)"} \
		{\rNO\ CARRIER\r} {error "Lost connection"}
}

proc disconnect { msg } {
	send "\r~.\r"
	send_user $msg
}