home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-06-12 | 53.8 KB | 1,843 lines |
- Newsgroups: comp.sources.unix
- From: Tom_Limoncelli@Warren.MENTORG.COM
- Subject: v26i059: tpage2 - tom's utilities for alphanumeric pagers (V2.0)
- Sender: unix-sources-moderator@pa.dec.com
- Approved: vixie@pa.dec.com
-
- Submitted-By: Tom_Limoncelli@Warren.MENTORG.COM
- Posting-Number: Volume 26, Issue 59
- Archive-Name: tpage2
-
- [ I don't have an alphanumeric pager so I couldn't test this. --vix ]
-
- Own an alpha-numeric pager? This will let your computer speak the protocol
- so you can send messages to it. With the help of a mail filter like
- "procmail" (available via ftp from your local comp.sources.unix archive or
- from berg@messua.informatik.rwth-aachen.de) you can have messages containing
- certain keywords automatically sent to your pager.
-
- Tom_Limoncelli@Warren.MENTORG.COM
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: README HISTORY INSTALL depend ixocico.c schedule
- # startdaemon table tpage.l tpage.pl tpaged.pl
- # Wrapped by vixie@cognition.pa.dec.com on Sat Jun 13 16:43:45 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(2173 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- READDME -- General information about "tpage"
- X by Tom Limoncelli, tal@warren.mentorg.com
- X Copyright (c) 1992, Tom Limoncelli
- X The sources can be freely copied for non-commercial use only
- X and only if the source is unmodified.
- X
- X"tpage" or "Tom's Pager System" is a set of programs that let
- you send messages to alpha-numeric pagers using the "IXO" protocol.
- It supports a dialing directory, a "who's on duty now" schedule,
- and can do special tricks with RFC822-format email.
- X
- The system has the following features:
- X
- X...sends pages to any pager system that supports the IXO protocol.
- X
- X...additional protocols can be added. (I'll write the touch-tone
- X protocol soon).
- X
- X...can parse email messages and extract the interesting info from
- X them resulting in shorter messages.
- X
- X...can copy it's input to stdout and therefore can be used as a "tee".
- X
- X...maintains a directory of people's phone numbers/PINs.
- X
- X...can page "the person on duty" (searches a schedule).
- X
- X...schedule can have slots that are empty, but find someone anyway if
- X the message is marked "urgent".
- X
- X...with programs like procmail, permits you to send certain email
- X messages to your pager.
- X
- X...a list of modems can be given to the daemon.
- X
- How it works (and how all the programs fit together):
- X
- o beep2.pl takes command-line and stdin, reads the schedule, looks
- X up people's paging info in the directory, and queues the message.
- o tpaged.pl should always be running. Every 30 seconds it wakes up
- X to check the queue for messages.
- o tpaged.pl then sorts and batches the messages.
- o tpaged.pl then calls the appropriate program to do the protocol
- X (currently that's ixocico but others can be written) and watches
- X the output for messages:
- X "#MESOK x" which means that message "x" was successful and can be
- X deleted from the queue.
- X "#MESREJECT x" which means that message "x" was rejected and should
- X be deleted from the queue. Email will be sent to the person
- X that sent the page.
- X
- XFor installation instructions, read INSTALL.
- XFor program history, read HISTORY.
- X
- If you aren't using "procmail", you're working too hard. Check
- X"archie" for a location near you!
- END_OF_FILE
- if test 2173 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'HISTORY' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'HISTORY'\"
- else
- echo shar: Extracting \"'HISTORY'\" \(994 characters\)
- sed "s/^X//" >'HISTORY' <<'END_OF_FILE'
- HISTORY
- X by Tom Limoncelli, tal@warren.mentorg.com
- X Copyright (c) 1992, Tom Limoncelli
- X The sources can be freely copied for non-commercial use only
- X and only if the source is unmodified.
- X
- XFor installation instructions, read INSTALL.
- XFor program history, read HISTORY.
- XFor general program information, read README.
- X
- X
- X(( This program is the successor to "fbeep".
- X((
- X(( fbeep history:
- X((
- X(( 1.0 Oct 29, 1991 -- First working version.
- X((
- X(( 1.1 Oct 30, 1991 -- Debugging levels implemented (-s -v -vv).
- X((
- X(( 1.2 Oct 30, 1991 -- Cleaned the output, error message on failure.
- X((
- X(( 1.3 Nov 20, 1991 -- Added -m, -M and "null person" options.
- X((
- X(( Made -a (abort) replace -w (wait).
- X((
- X(( 1.4 Jan 2, 1992 -- Destination can now be a list of people.
- X((
- X(( (project ended, replaced by tpage, tpaged, and ixocico)
- X
- X
- beep2.pl:
- X 1.0 Jan 31, 1992 -- First release.
- X
- tpaged.pl history:
- X 1.0 Jan 31, 1992 -- First release.
- X
- ixocico.c
- X 1.0 Jan 31, 1992 -- First release.
- X
- END_OF_FILE
- if test 994 -ne `wc -c <'HISTORY'`; then
- echo shar: \"'HISTORY'\" unpacked with wrong size!
- fi
- # end of 'HISTORY'
- fi
- if test -f 'INSTALL' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'INSTALL'\"
- else
- echo shar: Extracting \"'INSTALL'\" \(4323 characters\)
- sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
- INSTALL -- How to install the Tom Page set of programs.
- X by Tom Limoncelli, tal@warren.mentorg.com
- X Copyright (c) 1992, Tom Limoncelli
- X The sources can be freely copied for non-commercial use only
- X and only if the source is unmodified.
- X
- XFor program history, read HISTORY.
- XFor general program information, read README.
- X
- X
- THEORY OF OPERATION: (this assumes you've read README already)
- X--------------------
- X
- tpage.pl (which is often renamed to "beep" or "page") takes a number of
- options, figures out who and how to send to a person, figures
- out the message, and stuffs the info into a file for the daemon
- to read.
- X
- tpage.pl refers to /home/adm/lib/tpage/table to find out the phone
- number and other information that must be given to the daemon. You
- can also specify a different file name with the "-T" option.
- X
- tpaged.pl wakes up every couple minutes to see if there
- is anything new in the queue. If there is, it takes the information,
- dials out to your paging company, and transmits the message.
- X
- Rather than page a particular person, tpage.pl can be given a schedule
- and be told, "page whoever is on duty right now". This is done
- by giving it "-" as the "who" parameter. The schedule is stored
- in /home/adm/lib/tpage/schedule, or by specifying a file name with
- the "-S" option.
- X
- tpage can take the message from the command line, or from stdin. If
- it is coming from stdin, it can parse it as email and do various
- things with it (see the man page).
- X
- X
- INSTALLATION:
- X-------------
- X
- X1. Install the Perl programming language. The front-end to tpaged
- is written in Perl. Any version should do, but it was developed with
- version 4.019. Hopefully, this program already exists on your system.
- If not, I highly recommend that you get it from ftp.uu.net:/pub/gnu
- and install it.
- X
- XFor the rest of this document, $TPAGE will refer to the directory
- that you wish to keep the files associated with the tpage system.
- X
- ALL FILES SHOULD BE COPIED to $TPAGE except tpage (belongs in
- X/usr/local/bin/tpage). The queue directory should be $TPAGE/pqueue but
- nothing will break if you put it someplace else.
- X
- X2. Edit tpage.pl and copy it to "/usr/local/bin/tpage". The first
- section explains what variables need to be edited and why. You might
- want to call it "page" or "beep" instead.
- X
- XEdit tpaged.pl and copy it to "$TPAGE/tpage". The first
- section of each file explains what variables need to be edited and why.
- X
- XEdit tpage.l and copy it to "/usr/local/man/manl" or wherever local
- manpages are kept. The first section of each file explains what
- variables need to be edited and why.
- X
- If you run SunOS you won't have to edit ixocico.c. If you don't run SunOS
- you're going to have the fun of porting this program. I put in a couple
- of #defines to get you started. Anyway, compile it with a simple
- X"make ixocico" and you're done with it. ixocico doesn't require many
- edits because tpaged gives it everything it needs to know. ixocico
- also belongs in $TPAGE/ixocico
- X
- Copy the sample "table" file and copy it to $DEFAULT_T (which should
- be $TPAGE/table if you're smart). Read it. Then edit it to your
- requirements.
- X
- Copy the sample "schedule" file and copy it to $DEFAULT_S (which should
- be $TPAGE/schedule if you're smart). Read it. Then edit it to your
- requirements. You can edit this later or even skip this step if you
- don't care about the schedule feature.
- X
- X3. Read the man page ("nroff -man tpage.l | more").
- X
- X4. Create the $QUEUE_DIR directory (as defined in $TPAGE/tpage.pl and
- X$TPAGE/tpaged.pl) and do a chmod 0777 on it. Make sure that users on any
- machine that should be able to run "tpage" can create files there and
- delete at least their own files. If you use NFS you'll have to export
- that directory. If you don't use NFS, you're smart.
- X
- X5. Set up a cron job that runs "startdaemon" every 20 minutes on the
- machine with the modems. You might want to run it as root, you might
- want to run it as any user that can access those modems.
- X
- X6. Read the man page ("nroff -man tpage.l | more").
- X
- Test it and you're done. Try:
- X
- tpage -d 1xxxyyyzzzz -p 123456 "this is a test"
- X(substitute your phone number and pin)
- X
- tpage alias "this is a second test"
- X(replace "alias" with a name from the "table" file)
- X
- tpage - -
- this is a test using the schedule and stdin.
- X^D
- X
- X(this should page the "person on duty")
- X
- X
- END_OF_FILE
- if test 4323 -ne `wc -c <'INSTALL'`; then
- echo shar: \"'INSTALL'\" unpacked with wrong size!
- fi
- # end of 'INSTALL'
- fi
- if test -f 'depend' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'depend'\"
- else
- echo shar: Extracting \"'depend'\" \(390 characters\)
- sed "s/^X//" >'depend' <<'END_OF_FILE'
- What routines use on what routines
- X----------------------------------
- X
- safeprint:
- X
- checksum: safeprint
- X
- grabmodem:
- X
- send: safeprint
- X
- match: safeprint
- X
- hangup_modem: send
- X
- unlockmodem:
- X
- bail_out: hangup_modem unlockmodem
- X
- lockmodem: bail_out
- X
- getline: bailout safe_print
- X
- getpacket: bail_out safeprint
- X
- main: lockmodem grabmodem bail_out send match hangup_modem getpacket getline checksum
- X
- END_OF_FILE
- if test 390 -ne `wc -c <'depend'`; then
- echo shar: \"'depend'\" unpacked with wrong size!
- fi
- # end of 'depend'
- fi
- if test -f 'ixocico.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ixocico.c'\"
- else
- echo shar: Extracting \"'ixocico.c'\" \(12182 characters\)
- sed "s/^X//" >'ixocico.c' <<'END_OF_FILE'
- X/* ixocico -- IXO protocol call-in call-out.
- X** by Tom Limoncelli, tal@warren.mentorg.com
- X** Copyright (c) 1992, Tom Limoncelli
- X** The sources can be freely copied for non-commercial use only
- X** and only if they are unmodified.
- X**
- X** Version 1.0 -- See file HISTORY for details.
- X*/
- X
- X/****************************************************************/
- X/* USER CONFIGURABLE OPTIONS: */
- X
- X/* this should be "#define" if you use SunOS, or "#undef" if you
- X** use HPUX. This controls the name of LOCKDIR and if getpriority()
- X** is used. I'm sure more needs to be done, but that's a start.
- X*/
- X#define REAL_OS
- X
- X#ifdef REAL_OS
- X#define LOCKDIR "/var/spool/uucp"
- X#else
- X#define LOCKDIR "/usr/spool/locks"
- X/* That may not be correct */
- X#endif
- X
- X/* not talking to the modem correctly? Try mucking with
- the grabmodem() routine. */
- X
- X/* END OF USER CONFIGURABLE OPTIONS */
- X/****************************************************************/
- X
- X#include <stdio.h>
- X#include <fcntl.h>
- X#include <string.h>
- X/* #include <strings.h> */
- X#include <ctype.h>
- X#include <errno.h>
- X#include <sys/termios.h>
- X
- X#ifdef REAL_OS
- X#include <sys/time.h> /* required for <sys/resource.h> */
- X#include <sys/resource.h> /* required for getpriority() */
- X#endif
- X
- X/* ASCII constants */
- X#define STX (2)
- X#define EOT (4)
- X#define ACK (6)
- X#define LF (10)
- X#define CR (13)
- X#define NAK (21)
- X#define ESC (27)
- X#define RS (30)
- X
- X#define MAX_PACKET (10000) /* we'll never get a packet this big */
- X#define MAXLINE (1000)
- X
- X/* only two little global variables, how's that? */
- X
- int modem = 0;
- char *lockname = NULL;
- X
- X/* print a string without worrying about unprintable charactors */
- void
- safeprint(str)
- char *str;
- X{
- X while (*str) {
- X if (isgraph(*str))
- X (void) fprintf(stdout, "%c", *str);
- X else {
- X switch (*str) {
- X case LF:
- X (void) fprintf(stdout, "\\n");
- X break;
- X case CR:
- X (void) fprintf(stdout, "\\r");
- X break;
- X case 32:
- X (void) fprintf(stdout, "\\s");
- X break;
- X default:
- X (void) fprintf(stdout, "\\%d", *str);
- X break;
- X }
- X }
- X str++;
- X }
- X fflush(stdout);
- X}
- X
- X/* calculate checksum of a packet */
- char *checksum(pk)
- char *pk;
- X{
- X static char check[10];
- X int sum = 0;
- X
- X for (;*pk; pk++) sum += *pk;
- X check[2] = '0' + (sum & 15); sum = sum >> 4;
- X check[1] = '0' + (sum & 15); sum = sum >> 4;
- X check[0] = '0' + (sum & 15);
- X check[3] = 0;
- X
- printf("CHECKSUM=:"); safeprint(check); printf(":\n");
- X return check;
- X}
- X
- X/* open the modem. You should have done a lockmodem() first */
- int grabmodem(dev)
- char *dev;
- X{
- X struct termios ti;
- X int modem;
- X
- X errno = 0;
- X modem = open(dev, O_RDWR, 0);
- X if (errno) {
- X printf("#MODOPEN modem can't be opened\n");
- X return 0;
- X }
- X
- X /* set tty params to 300bps, even parity, 7-1-e */
- X errno = 0;
- X ioctl(modem, TCGETS, &ti);
- X if (errno) {
- X close(modem);
- X return 0;
- X }
- X ti.c_iflag |= IGNBRK; /* ignore breaks */
- X /* ti.c_iflag |= IGNPAR; *//* ignore parity */
- X ti.c_iflag &= ~INPCK; /* ignore parity errors */
- X ti.c_iflag |= ISTRIP; /* strip 8th bit */
- X ti.c_iflag &= ~INLCR; /* don't cr->nl */
- X ti.c_iflag &= ~ICRNL; /* don't cr->nl */
- X ti.c_iflag &= ~IGNCR; /* don't ignore cr */
- X /* ti.c_iflag &= ~IXON; *//* don't do xon */
- X /* ti.c_iflag &= ~IXOFF; *//* don't do xoff */
- X
- X ti.c_oflag &= ~OPOST; /* don't post-process */
- X
- X ti.c_cflag &= ~CBAUD; /* baud=300 */
- X ti.c_cflag |= B300;
- X ti.c_cflag &= ~CSIZE; /* 8-bit bytes */
- X ti.c_cflag |= CS8;
- X ti.c_cflag &= ~CSTOPB; /* one stop bit */
- X ti.c_cflag &= ~PARENB; /* parity */
- X ti.c_cflag &= ~PARODD; /* even parity */
- X ti.c_cflag |= HUPCL; /* hang up on last close */
- X /* ti.c_cflag |= CRTSCTS; *//* hardware handshaking */
- X ti.c_cc[VMIN] = 0; /* read() can get as few as 0 bytes */
- X ti.c_cc[VTIME] = 50; /* time out at 5 seconds no matter what */
- X
- X ti.c_lflag &= ~ISIG; /* disable signals */
- X ti.c_lflag &= ~ICANON; /* disable signals */
- X ti.c_lflag &= ~ECHO; /* don't echo */
- X
- X errno = 0;
- X ioctl(modem, TCSETS, &ti);
- X if (errno) {
- X close(modem);
- X return 0;
- X }
- X return modem;
- X}
- X
- X/* send data to the modem */
- void send(fd, str)
- int fd;
- char *str;
- X{
- X printf("Sending: :"); safeprint(str); printf(":\n", str);
- X write(fd, str, strlen(str));
- X}
- X
- X/* wait for a particular string from the modem (err = # of times to re-try) */
- int match(mod, str, err)
- X int mod;
- X char *str;
- X int err;
- X{
- X int len;
- X char c;
- X
- printf("MATCHING on :"); safeprint(str); printf(":\n", str);
- X
- X while (1) {
- X c = 0;
- X/* printf("waiting for :%c:\n", *str); */
- X len = read(mod, &c, 1);
- X if (len) {
- X/* printf("got=%d:%c\n", c,c); */
- X if (c == *str) str++;
- X if (!(*str)) break; /* matched all? Exit loop */
- X }
- X if (!err--) {
- X printf("NOT MATCHED\n");
- X return 1;
- X }
- X }
- printf("MATCHED\n");
- X return 0;
- X}
- X
- X/* hang up the modem */
- void
- hangup_modem(fd)
- int fd;
- X{
- X sleep(3);
- X send(fd, "+++");
- X sleep(3);
- X send(fd, "ATH\r");
- X sleep(1);
- X}
- X
- X/* unlock the modem */
- void unlockmodem(name)
- char *name;
- X{
- X printf("Unlocking modem.\n");
- X (void)unlink(name);
- X return;
- X}
- X
- X/* clean up and leave this program */
- void bail_out()
- X{
- X if (modem) {
- X hangup_modem(modem);
- X close(modem);
- X }
- X if (lockname) unlockmodem(lockname);
- X exit(0);
- X}
- X
- X/* lock the modem OR DIE*/
- char *lockmodem(dev)
- char *dev;
- X{
- X int lock, pid;
- X int failcnt = 3;
- X char waitcnt = 0;
- X char *lkn, lname[200];
- X
- X strcpy(lname, LOCKDIR);
- X strcat(lname, "/LCK..");
- X strcat(lname, 1 + rindex(dev, '/'));
- X
- printf("Lockfile = %s\n", lname);
- X lkn = strdup(lname);
- X while (failcnt--) {
- X errno = 0;
- X lock = open(lname, O_CREAT | O_WRONLY | O_EXCL, 0777);
- X if (lock == -1) {
- X#ifdef REAL_OS
- X printf("Modem is locked, attempting to steal.\n");
- X /* locked, let's read the cookie in the lock */
- X pid = 0;
- X if ((lock = open(lname, O_RDONLY)) != -1) {
- X (void)read(lock, &pid, sizeof(int) );
- X printf("Device is locked by process %d\n", pid);
- X close(lock);
- X }
- X printf("Lock = %d\n", lock);
- X if (pid < 3) {
- X printf("#MODOPEN device is locked by pid < 3\n");
- X bail_out();
- X }
- X /* see if the process still is alive */
- X errno = 0;
- X (void) getpriority(PRIO_PROCESS, pid);
- X if (errno == ESRCH) { /* lock process dead, let's go! */
- X if (unlink(lname)) {
- X printf("#MODOPEN Can't steal lock.\n");
- X bail_out();
- X } else {
- X printf("Lock is stale, stealing!\n");
- X }
- X } else {
- X printf("#MODOPEN Valid lock in the way.\n");
- X bail_out();
- X }
- X#else
- X printf("#MODOPEN it's locked, I'm out of here!\n");
- X bail_out();
- X#endif
- X } else {
- X /* lock opened, stuff and go */
- X pid = getpid();
- X write(lock, &pid, sizeof(int));
- X close(lock);
- X break;
- X }
- X }
- X if (failcnt==-1) {
- X printf("#MODOPEN Couldn't lock modem after many tries.\n");
- X bail_out();
- X }
- X return lkn;
- X}
- X
- X/* get a line from stdin OR DIE */
- char *getline(line)
- char *line;
- X{
- X int len;
- X char *r;
- X
- X /* get a line, if EOF return 0 */
- X if (!(r = fgets(line, MAXLINE, stdin))) return 0;
- X
- X printf("Data in queue=:"); safeprint(line); printf(":\n", line);
- X
- X if (!(len = strlen(line))) {
- X printf("#BADQUEUE Blank line in queued data\n");
- X bail_out();
- X }
- X
- X if (line[len-1] == '\n') {
- X line[len-1] = 0;
- X } else {
- X /* if fgets didn't return a string ending in \n */
- X printf("#BADQUEUE Data in queue has line too long\n");
- X bail_out();
- X }
- X return r;
- X}
- X
- X/* Loop until you get a valid packet. If you get a "message sequence" then
- display it. If you get an invalid pack DIE */
- X
- void getpacket(fd, str)
- int fd;
- char *str;
- X{
- X int max;
- X char c;
- X int len;
- X char *buf = str;
- X int err;
- X
- X *str = 0;
- X err=50; /* permit up to 500 message sequences or bad packets */
- X while (err--) {
- X printf("Getting packet\n");
- X max = MAX_PACKET;
- X while (read(fd, &c, 1) == 1) {
- X if (c == LF) continue; /* skip LF's */
- X if (c == CR) {
- X /* don't actually put CR in the string */
- X break;
- X }
- X *buf++ = c;
- X max--;
- X if (!max) {
- X /* packet was too long */
- X printf("#PACKLEN packet was too long\n");
- X bail_out();
- X }
- X }
- X *buf = 0;
- X len = buf - str;
- X if (len) {
- X printf("Got packet--length=%d\n", len);
- X if (isgraph(*str)) {
- X printf("#GOTMESSEQ message sequece=:");
- X safeprint(str);
- X printf(":\n");
- X } else {
- X /* print packet contents */
- X printf("packet is data=:"); safeprint(str); printf(":013:\n");
- X return;
- X }
- X }
- X }
- X printf("#LONELY It's too quiet in here. Disconnecting.\n");
- X bail_out();
- X}
- X
- int main(argc, argv)
- int argc;
- char *argv[];
- X{
- X char dialstring[MAX_PACKET];
- X char *pack = dialstring; /* use same workspace */
- X char line[MAXLINE+1];
- X char pin[MAXLINE+1];
- X char mesg[MAXLINE+1];
- X int mesnum, failcnt, len;
- X char c;
- X
- X /* check arguments */
- X if (argc != 3) {
- X printf("#WRONGARGS wrong number of arguments\n");
- X bail_out();
- X }
- X
- X /* lock modem or die */
- X lockname = lockmodem( argv[1] );
- X /* open modem or die */
- X printf("opening modem\n");
- X modem = grabmodem( argv[1] );
- X if (!modem) bail_out();
- X
- X /* see if modem is awake or hangup; after 3 tries die */
- X failcnt = 3;
- X while (failcnt--) {
- X send(modem, "AT\r");
- X if (match(modem, "OK", 9)) {
- X printf("No response. Hang up and try again.\n");
- X hangup_modem(modem);
- X while (read(modem, &c, 1)) { /*DONOTHING*/ };
- X } else break;
- X }
- X if (failcnt==-1) bail_out();
- X
- printf("dialing\n");
- X
- X /* send the "A" of "ATDT" */
- X do {
- X send(modem, "A");
- X } while (match(modem, "A", 2));
- X /* send the rest of the dial string */
- X sprintf( dialstring, "TDT%s\r", argv[2] );
- X send(modem, dialstring);
- X (void) match(modem, argv[2], 10);
- X
- X /* wait for the modem to connect */
- X printf("waiting for CONNECT\n");
- X if (match(modem, "CONNECT", 400)) {
- X printf("#NOCONN no connect\n");
- X bail_out();
- X }
- X
- printf("Waiting for ID=\n");
- X
- X /* send a CR ever second until "ID=" comes back */
- X while (1) {
- X if (match(modem, "ID=", 100)) send(modem, "\r");
- X else break;
- X }
- X
- printf("Logging in\n");
- X
- X failcnt = 3;
- X while (failcnt--) {
- X /* switch to "automatic protocol" */
- X printf("Sending ESC\n");
- X write(modem, "\033", 1);
- X send(modem, "PG1000000\r");
- X
- X printf("Waiting for acceptance (aren't we all)\n");
- X getpacket(modem, pack);
- X len = strlen(pack);
- X if ((len==1) && (*pack == ACK)) {
- X printf("login successful\n");
- X break;
- X }
- X if ((len==1) && (*pack == NAK)) {
- X printf("retrying to log in.\n");
- X continue;
- X }
- X if ((len==2) && (*pack == ESC) && (pack[1] == EOT)) {
- X printf("forced disconnect\n");
- X bail_out();
- X }
- X printf("#UNKNOWNPROTO not the response we're looking for. Disconnecting.\n");
- X bail_out();
- X }
- X if (failcnt==-1) bail_out();
- X
- printf("waiting for message go ahead\n");
- X failcnt=40;
- X while (failcnt--) {
- X getpacket(modem, pack);
- X if (!strcmp(pack, "\033[p")) break;
- X }
- X if (failcnt==-1) bail_out();
- X printf("got message go-ahead\n");
- X
- X for (mesnum=0; getline(pin); ) {
- X getline(mesg);
- X failcnt=100;
- X while (failcnt--) {
- X /* build the packet to be sent */
- X pack[0] = STX;
- X pack[1] = 0;
- X strcat(pack, pin);
- X strcat(pack, "\r");
- X strcat(pack, mesg);
- X strcat(pack, "\r\3"); /* CR then ETX */
- X strcat(pack, checksum(pack));
- X strcat(pack, "\r");
- X send(modem, pack);
- X
- X /* wait for response and deal */
- X printf("waiting for validation\n");
- X getpacket(modem, pack);
- X len = strlen(pack);
- X if ((len==1)&&(*pack==ACK)) {
- X printf("#MESOK %d message xmitted fine\n", mesnum++);
- X break;
- X } else if ((len==1)&&(*pack==NAK)) {
- X printf("re-retrying message %d\n", mesnum);
- X } else if ((len==1)&&(*pack==RS)) {
- X printf("#MESREJECT %d message rejected\n", mesnum++);
- X break;
- X } else if ((len==2)&&(*pack==ESC)&&(*pack==EOT)) {
- X printf("#FORDIS forced disconnect\n");
- X bail_out();
- X }
- X }
- X if (failcnt==-1) {
- X printf("#PROTERR couldn't send packets\n");
- X bail_out();
- X }
- X }
- X printf("#DONE we're done. Logging out.\n");
- X send(modem, "\4\r"); /* EOT then CR */
- X
- X failcnt=3;
- X while (failcnt--) {
- X printf("waiting for system logout\n");
- X getpacket(modem, pack);
- X len=strlen(pack);
- X if ((len==2) && (pack[0] == ESC) && (pack[1] == EOT)) {
- X printf("#BYE asked to hangup\n");
- X bail_out();
- X }
- X if ((len==1)&&(*pack==RS)) {
- X printf("#WRONGANY something went wrong. (useless msg)\n");
- X bail_out();
- X }
- X/* if (!stricmp(line, "NO CARRIER")) break; */
- X }
- X printf("#BYE we're leaving.\n");
- X bail_out();
- X}
- X
- X
- END_OF_FILE
- if test 12182 -ne `wc -c <'ixocico.c'`; then
- echo shar: \"'ixocico.c'\" unpacked with wrong size!
- fi
- # end of 'ixocico.c'
- fi
- if test -f 'schedule' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'schedule'\"
- else
- echo shar: Extracting \"'schedule'\" \(2140 characters\)
- sed "s/^X//" >'schedule' <<'END_OF_FILE'
- X# beepersched -- the schedule of who's on-call at what times.
- X# [For use with tpage.pl -- By Tom Limoncelli (tal@warren.mentorg.com)]
- X#
- X# This file is only used if "who" is "-"
- X#
- X# The lines that begin with 0-6 refer to the days Sun-Sat. The 48
- X# bytes after refer to who's on duty each half-hour.
- X#
- X# This schedule shows tal, ingo, and greg as
- X# having different hours. On Monday night, all three are paged.
- X#
- X# A "-" in this list (not to be confused with "-" on the command
- X# line) means "no body is on duty". If the "-U" (urgent) is used,
- X# beep2.pl keeps looking for another schedule to see if maybe it
- X# can find someone else scheduled for that time. The way I manage
- X# things is to have lower-case letters mean individual people and
- X# capitol letters meaning the fall-back "urgent" people (usually a list
- X# of the person and their fallback). For example, "g" is for greg,
- X# and "G" is for greg and the person that backs him up.
- X# Of course, you can use any system you wish.
- X#
- X# N
- X# O
- X# 1 1 O 1 1
- X#0 1 2 3 4 5 6 7 8 9 0 1 N 1 2 3 4 5 6 7 8 9 0 1
- X0--------------------ttttttttttttttttAAAAAAAAAAAA
- X1------------ttttgggttttttggggiiiiiiitt----------
- X2------------ttttgggttttttggggiiiiiiitttttttttttt
- X3------------ttttgggttttttggggiiiiiiitt----------
- X4------------ttttgggttttttggggiiiiiiitttttttttttt
- X5------------ttttgggttttttggggiiiiiiitt----------
- X6-------------------tttttttttttttttttttttttttt---
- X#
- X# these will only be accessed if -U is used.
- X# A "-" in this list means "don't call anyone"
- X#
- X# 1 1 O 1 1
- X#0 1 2 3 4 5 6 7 8 9 0 1 N 1 2 3 4 5 6 7 8 9 0 1
- X0TTTTTTTTTTTTTTTTTTT--------------TTTTTTTTTTTTTTT
- X1TTTTTTTTTTTTTTTTTTT--------------TTTTTTTTTTTTTTT
- X2TTTTTTTTTTTTTTTTTTT--------------TTTTT----------
- X3TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
- X4TTTTTTTTTTTTTTTTTTT--------------TTTTT----------
- X5TTTTTTTTTTTTTTTTTTT--------------TTTTTTTTTTTTTTT
- X6TTTTTTTTTTTTTTTTTTT--------------TTTTTTTTTTTTTTT
- X#
- X#
- g=greg
- i=ingo
- t=tal
- X#
- X# a person and their backup
- G=greg,tal
- I=ingo,greg
- T=tal,greg
- X#
- A=greg,tal,ingo
- END_OF_FILE
- if test 2140 -ne `wc -c <'schedule'`; then
- echo shar: \"'schedule'\" unpacked with wrong size!
- fi
- # end of 'schedule'
- fi
- if test -f 'startdaemon' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'startdaemon'\"
- else
- echo shar: Extracting \"'startdaemon'\" \(595 characters\)
- sed "s/^X//" >'startdaemon' <<'END_OF_FILE'
- X#! /usr/local/bin/perl4.019
- X
- X# "start daemon" -- Start the tpaged daemon if it isn't running.
- X# by Tom Limoncelli, tal@warren.mentorg.com
- X# Copyright (c) 1992, Tom Limoncelli
- X
- X
- X$BSD = -f '/vmunix';
- X$pscmd = $BSD ? "ps -auxww" : "ps -ef";
- X
- open(PS, "$pscmd|") || die "Can't run ps: !$";
- X$title = <PS>;
- X$found = 0;
- while (<PS>) {
- X chop;
- X $found = 1 if /tpaged/;
- X}
- X
- if (!$found) {
- X unless (fork) { # this is the child
- X unless (fork) { # this is the child's child
- X sleep 1 until getppid == 1;
- X system "/home/adm/lib/tpage/tpaged &";
- X exit 0;
- X }
- X exit 0;
- X }
- X print "Started tpaged\n";
- X}
- END_OF_FILE
- if test 595 -ne `wc -c <'startdaemon'`; then
- echo shar: \"'startdaemon'\" unpacked with wrong size!
- fi
- chmod +x 'startdaemon'
- # end of 'startdaemon'
- fi
- if test -f 'table' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'table'\"
- else
- echo shar: Extracting \"'table'\" \(623 characters\)
- sed "s/^X//" >'table' <<'END_OF_FILE'
- X# beepertab -- table of information about people's beepers.
- X# [ For use with tpage.pl by Tom Limoncelli (tal@warren.mentorg.com)]
- X#
- X# Comment lines begin with "#".
- X#
- X# The columns are name, numeric pager phone # (currently unused), IXO
- X# protocol number to dial, and the person's pagerid.
- X#
- X# Aliases are implemented by repeating data. (ooo, fancy!)
- X#
- greg 5551212 18006789012 1234567
- gregt 5551212 18006789012 1234567
- X#
- ingo 5551213 18006789012 7654321
- idean 5551213 18006789012 7654321
- X#
- tom 5551214 18006789012 1122334
- tal 5551214 18006789012 1122334
- END_OF_FILE
- if test 623 -ne `wc -c <'table'`; then
- echo shar: \"'table'\" unpacked with wrong size!
- fi
- # end of 'table'
- fi
- if test -f 'tpage.l' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tpage.l'\"
- else
- echo shar: Extracting \"'tpage.l'\" \(6781 characters\)
- sed "s/^X//" >'tpage.l' <<'END_OF_FILE'
- X.ds l local
- X.TH TPAGE N "30 Jan 1992"
- X.BY "Tom Limoncelli, tal@warren.mentorg.com"
- X.SH NAME
- tpage \- front-end to Tom's Pager System
- X.br
- tpaged \- daemon that manages paging queue
- X.br
- ixocico \- program that executes the IXO protocol
- X.SH SYNOPSIS
- X.B /usr/local/bin/tpage
- X[
- X.B \-T
- table file
- X] [
- X.B \-S
- schedule file
- X] [
- X.B \-U
- X] [
- X.B \-d
- phone num
- X] [
- X.B \-p
- pin
- X] [
- X.B \-t
- X] [
- X.B \-v
- X] [
- X.B \-m
- X] [
- X.B \-M
- X] [
- X.B \-e
- X]
- X.B who
- X[
- X.B message
- or
- X.B \-
- X]
- X.br
- X.B /home/adm/lib/tpage/tpaged
- X.br
- X.B /home/adm/lib/tpage/ixocico
- dev phonenum
- X.br
- X.SH DESCRIPTION
- X.I tpage
- is the front-end to the system. A user can run this program to
- submit a message to someone's pager.
- X.PP
- The program wants 4
- things: (1) the phone number to dial, (2) the person's PIN
- pin (Personal Identification Number), (3) who to email if the
- page isn't accepted, and (4) the message.
- X.PP
- Once it has all that information, it dumps it into a file
- which is read by
- X.B tpaged
- which delivers the message to the paging service using
- the appropriate protocol. tpaged selects the correct
- program for you. Each protocol is implemented as
- a separate program. Currently \fBixocico\fR
- is the only program to choose from, and it implements
- the IXO protocol.
- X.PP
- The phone
- number (1) and PIN (2) can be specified with the
- X.B \-d
- and
- X.B \-p
- options, OR by specifying a name (which instructs tpage
- to look up the information in the pager table file), OR by
- specifying the name ``\-'' which
- means ``whoever is on duty'' (which instructs tpage to find
- out who is on duty from the schedule file, and then look up
- their phone number and PIN in the pager table file).
- X.PP
- Specifying a phone number without a PIN (or vice-versa) results
- in the missing data being looked up in the pager table file.
- X.PP
- A comma-separated list of names may be given. It is much more
- efficient to use a list of names than to do single pages.
- X.PP
- NOTE: A name must always be specified, so if you use the
- X.B \-d
- and
- X.B \-p
- options you must also specify a name (such as ``foo'') which will
- be ignored. Combining a list of names with the
- X.B \-d
- and/or
- X.B \-p
- options works in a logical but undefined manner.
- X.PP
- To specify who to email if there is a problem (3) use the
- X.B \-e
- option. The default for this is to not send email to anyone.
- X.PP
- The message (4) can be specified on the command line or if ``-'' is
- given, stdin is read for the message. No matter how many
- bytes you give it, the high-bit is stripped, RETURNs and TABs are
- turned into spaces, and groups of spaces are turned into single
- spaces. The first 160 bytes (configurable in the program) is
- all that's sent, since that's all that the pager will display.
- X.PP
- Command-line options are:
- X.TP 10
- X.BR \-T " table file"
- X\fItable file\fR is the file that has the
- table of people and the info needed to communicate
- with their pager. The default is /home/adm/lib/tpage/table.
- X.TP
- X.BR \-S " schedule file"
- X\fIschedule file\fR is the file that has the
- is the file that is used
- to find out who's on duty at this moment. This file is only
- consulted if ``who'' is ``\-''. The default is
- X/home/adm/lib/tpage/schedule.
- X.TP
- X.B \-U
- This option marks the message as \fIurgent\fR. If the schedule
- lists that no one is on duty at that time but the message is
- marked \fIurgent\fR, a secondary schedule is consulted.
- X.TP
- X.BR \-d " phone num"
- Ignore what the table file says, use this phone number when
- dialing. If a list of people is specified, this phone number
- is used for the first person, the others will be looked
- up in the \-T file.
- X.TP
- X.BR \-p " pin"
- Ignore what the table file says, use this PIN when transmitting
- the message.
- If a list of people is specified, this phone number
- is used for the first person, the others will be looked
- up in the \-T file.
- X.TP
- X.B \-t
- Act as a ``tee''. Copy stdin to stdout. If you give this
- option and the message is not coming from
- X.TP
- X.B \-v
- Verbose mode. Currently useless since there isn't anything
- extra worth printing.
- X.TP
- X.B \-m
- Parse the input as mail. Skip all the headers but extract the ``From'',
- X``Subject'', and ``Priority'' lines. If they exist, append to the
- beginning of the message ``F: frominfo'', ``S: subject line'',
- X``P: priority''. ``F:'' and ``P:'' are clipped to be one screenful
- in length. They are all padded out to the end of the screen.
- X.TP
- X.B \-M
- Skip ``mail quoted'' lines. Netnews and Mail often have other messages
- quoted by prefixing each line with greater than symbol. This option
- skips any input line that begins with zero or more whitespace charactors,
- followed by zero or more letters or numbers, followed by zero or more
- of \<, \>, {, or }. This should catch the normal quoting methods
- as well as anything the perverse superquote.el package
- for GNU Emacs
- might come up with.
- X.TP
- X.B \-e
- On error, send email to this person. If any errors happen when
- the tpage command is beign run, the user is notified. This
- is for sending email when the page is being processed. In
- other words, if the PIN is incorrect. If the phone number is
- incorrect the tpaged daemon will keep redialing and redialing it
- trying to figure out why it can't get through.
- X.PP
- X.IR tpaged
- tpage is a program that you don't need to know about. Your
- sysadmin should have installed it for you. It wakes up about
- every 20 seconds, sees if there are any new messages to send
- out and tries to send them. It can understand multiple paging
- protocols (tpage picks the best one for you) though it
- currently only knows about the IXO protocol. tpage can run
- as ``root'' but is often just run as ``daemon''.
- X.PP
- X.IR ixocico
- is the message transport program for the tpage system. It is called
- by
- X.B tpaged
- and told what device to use and what phone number to dial on
- the command line. It
- gets the PINs and messages to send from stdin.
- X.PP
- It co-exists with the uucp programs fine as it uses the
- same methods to lock the modems. It notices stale locks
- and blows them away. Not all locking features have been
- proven to work on HPUX, only SunOS.
- It will not wait for a modem to be unlocked.
- X.PP
- X.B tpaged
- watches the output of
- X.B ixocico
- for lines beginning with # to know success
- or failure of particular messages and of the entire batch.
- X.PP
- X.SH FILES
- X.ta 6c
- X.nf
- X/home/adm/lib/tpage/schedule schedule of who's on duty
- X/home/adm/lib/tpage/table table of people and their pager info
- X.SH SEE ALSO
- uucico(1), xkill(l)
- X.SH HISTORY
- Written by Tom Limoncelli (tal@Warren.MENTORG.COM)
- at Mentor Graphics Corporation, Silicon Design Division,
- Warren, New Jersey. May be re-distributed only in it's unmodified
- form.
- X.SH BUGS
- If
- X.B \-d
- and
- X.B \-p
- are specified, a name still must be specified.
- X.PP
- It currently only compiles under SunOS even though some
- defines are inserted so that it doesn't fail all over the
- place on silly operating systems like HPUX.
- END_OF_FILE
- if test 6781 -ne `wc -c <'tpage.l'`; then
- echo shar: \"'tpage.l'\" unpacked with wrong size!
- fi
- chmod +x 'tpage.l'
- # end of 'tpage.l'
- fi
- if test -f 'tpage.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tpage.pl'\"
- else
- echo shar: Extracting \"'tpage.pl'\" \(9757 characters\)
- sed "s/^X//" >'tpage.pl' <<'END_OF_FILE'
- X#! /usr/local/bin/perl4.019
- X
- X# tpage.pl -- front-end to tpage system.
- X# by Tom Limoncelli, tal@warren.mentorg.com
- X# Copyright (c) 1992, Tom Limoncelli
- X# The sources can be freely copied for non-commercial use only
- X# and only if they are unmodified.
- X
- X# Version 1.0 -- See file HISTORY for details.
- X
- X####################################################################
- X#
- X# Parameters that the user can set:
- X#
- X####################################################################
- X
- X$debug = 0;
- X# leave that off
- X
- X$MAX_WINDOW = 16;
- X#This is the number of charactors at a time do you see on your
- X# pager. This is used when word-wrapping.
- X
- X$MAX_MESSAGE = 160;
- X# How many bytes can one message be. This must be less than 250
- X# minus the length of your PIN. This is because each packet in the ixo
- X# protocol must be less than 250 chars. If you have a pager that can
- X# receive longer messages, you'll have to modify the ixocico.c program
- X# to handle the "packet continuation" feature. No biggie, just
- X# something that I didn't feel like implementing since I can't even
- X# test it with my pager.
- X
- X$DEFAULT_S = '/home/adm/lib/tpage/schedule';
- X# (default: '/home/adm/lib/tpage/schedule')
- X# If you plan on using the schedule feature, this is the file
- X# name where beep2.pl will look for the schedule. It must be accessable
- X# on the machine that runs tpage.pl, not the machine that runs the
- X# daemon (tpaged.pl).
- X
- X$DEFAULT_T = '/home/adm/lib/tpage/table';
- X# (default: '/home/adm/lib/tpage/table')
- X# If you plan on using the table feature (that is, store a list
- X# of people and their paging info), this is the file name where tpage.pl
- X# will look for the data. It must be accessable on the machine that
- X# runs tpage.pl, not the machine that runs the daemon (tpaged.pl).
- X
- X$QUEUE_DIR = '/home/adm/lib/tpage/pqueue/';
- X# (default: '/home/adm/lib/tpage/pqueue/'
- X# This is the directory where messages will be queued. The trailing "/"
- X# is required.
- X
- X####################################################################
- X# some helping functions
- X
- require("getopts.pl");
- X
- sub strip_string {
- X local($s) = @_;
- print "DEBUG: REMOVE_CONTROLS :", $s, ":\n" if $debug;
- X $s =~ tr/\200-\377/\000\177/; # remove high-bit
- X $s =~ tr/\000-\037\177//d; # delete unprintables
- X $s =~ s/\s+/ /g; # change groups of white space into " "
- X $s =~ s/^ //; # remove spaces from the front
- X $s =~ s/ $//; # remove spaces from the end
- X
- print "DEBUG: REMOVE_DONE :", $s, ":\n" if $debug;
- X return $s;
- X}
- X
- X####################################################################
- X# Here's the actual program
- X
- X####################################################################
- X# Get the command line options.
- X
- X# set the defaults
- X
- print "\n";
- X
- X# -S schedule file
- X$opt_S = $DEFAULT_S;
- X# -T pager table
- X$opt_T = $DEFAULT_T;
- X# -U use urgent schedule if no one is scheduled for that time.
- X$opt_U = 0;
- X# -d number to dial. (first name in list only)
- X$opt_d = "";
- X# -p pager id to use. (first name in list only)
- X$opt_p = "";
- X# -t tee all stdin into stdout.
- X$opt_t = 0;
- X# -v verbose mode.
- X$opt_v = 0;
- X# -m input will be in RFC822, skip boring stuff.
- X$opt_m = 0;
- X# -M like -m but also skip >-quoted text.
- X$opt_M = 0;
- X# -e if it errors, send email to this person.
- X$opt_e = "";
- X
- X$line_from = "";
- X$line_subj = "";
- X$line_prio = "";
- X
- do Getopts('S:T:Ud:p:tvmMe:');
- X
- X# get the wholist
- X$opt_wholist = shift (@ARGV);
- X$opt_wholist = "special" if $opt_d && $opt_p;
- X
- X####################################################################
- X# Get the message (either on the command line or stdin; handle -t -m -M
- X
- X# bunch up all the rest
- X$opt_message = join(' ', @ARGV);
- print "opt_message = :$opt_message:\n" if $debug;
- X$opt_message = &strip_string( $opt_message ) if $opt_message;
- print "opt_message = :$opt_message:\n" if $debug;
- die "$0: No message. Cat got your tongue?" if ( $opt_message eq "" );
- X
- die "$0: Can't use -m/-M and have message on the command line"
- X if ($opt_m || $opt_M) && $opt_message ne '-';
- X
- X# maybe get message from stdin, echoing to stdout if $opt_t;
- if ($opt_message eq '-') {
- X $opt_message = '';
- X # handle -m headers first
- X if ($opt_m) {
- X print "DEBUG: Doing -m work\n" if $debug;
- X local($line) = "";
- X while (<>) {
- X if ( /^\S/ || /^$/ ) { # start of new header, do previous one
- X $line_from = substr($line, 6) if $line =~ /^From/;
- X $line_subj = substr($line, 9) if $line =~ /^Subject: /;
- X $line_prio = substr($line, 10) if $line =~ /^Priority: /;
- X $line = $_;
- X } else {
- X $line .= $_;
- X }
- X last if /^$/; # end of headers, start processing
- X }
- X }
- X $line_from = &strip_string( $line_from ) if $line_from;
- X $line_subj = &strip_string( $line_subj ) if $line_subj;
- X $line_prio = &strip_string( $line_prio ) if $line_prio;
- X
- X while (<>) {
- X# -M means skip if the line is news quoted email.
- X# a line is news quoted if it begins with one of the following:
- X# [white] [word] quote
- X# where "white" is any amount of whitespace (zero or one times)
- X# where word is any letters/numbers (userid) (zero or one times)
- X# where quote is any of >, <, }, or {.
- X next if $opt_M && /^\s*\S*[\>\}\<\{]/;
- X print if $opt_t;
- X $_ = &strip_string( $_ );
- X $opt_message .= $_;
- X $opt_message .= " ";
- X # once we've got quite a bunch, screw the rest.
- X if ( length($opt_message) > ($MAX_MESSAGE * 8)) {
- X while (<>) { print if $opt_t; }
- X }
- X }
- X}
- X
- X####################################################################
- X# massage the message
- X
- if ($debug) {
- X print "DEBUG: pre-processed messages\n";
- X print "FROM=:$line_from:\n";
- X print "PRIO=:$line_prio:\n";
- X print "SUBJ=:$line_subj:\n";
- X print "MESS=:$opt_message:\n";
- X}
- X
- X$line_from = substr( "F: " . $line_from . ' ' x $MAX_WINDOW,
- X 0, $MAX_WINDOW) if $line_from; # pad to display size
- X
- X$line_prio = substr( "P: " . $line_prio . ' ' x $MAX_WINDOW,
- X 0, $MAX_WINDOW) if $line_prio; # pad to display size
- X
- X$l = $MAX_WINDOW * int ((length($line_subj)+$MAX_WINDOW+2) / $MAX_WINDOW);
- X$line_subj = substr( "S: " . $line_subj . ' ' x $MAX_WINDOW,
- X 0, $l) if $line_subj; # pad to display size
- X
- X$opt_message = &strip_string( $opt_message );
- X# put it all together
- X$the_message = substr( $line_prio . $line_from . $line_subj . $opt_message, 0, $MAX_MESSAGE);
- X
- if ($debug) {
- X print "DEBUG: post-processed messages\n";
- X print "FROM=:$line_from:\n";
- X print "PRIO=:$line_prio:\n";
- X print "SUBJ=:$line_subj:\n";
- X print "MESS=:$opt_message:\n";
- X print "COMPLETE=:$the_message:\n";
- X}
- X
- X####################################################################
- X# At this point we can do some more of the sanity checking.
- X
- X#die "$0: Conflicting verbosity levels" if ($opt_s && ($opt_v || $opt_V));
- die "$0: Schedule file $opt_S can't be read/found"
- X unless ( ($opt_wholist eq '-') || (-r $opt_S && -r $opt_T) );
- die "$0: Pager table $opt_T can't be read"
- X unless ($opt_d && $opt_p) || ( -r $opt_T );
- X
- X####################################################################
- X# use the schedule to fill in "who" if we need.
- X
- if ($opt_wholist eq '-') {
- X local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
- X local($l) = $wday;
- X local($h) = $hour * 2 + int ($hour / 30) + 1;
- X local($w,$found1) = 0;
- X
- print "L = $l\n" if $debug;
- print "H = $h\n" if $debug;
- print "U = $opt_U\n" if $debug;
- X
- X # Read from schedule until you hit a line beginning with $l.
- X # At that point, get the char $h bytes in. If that byte is "-",
- X # and $opt_U, keep going.
- X print "\nChecking schedule:\n\n";
- X open(SCHED, "<$opt_S") || die "Can't open $opt_S: $!";
- X while (1) {
- X $w = '';
- X while (<SCHED>) {
- X last if /^${l}/;
- X }
- X $w = substr($_, $h, 1);
- X $found1 = 1 if $w; # we found one!
- X next if $opt_U && $w eq '-';
- X last;
- X }
- X
- X die "$0: Schedule doesn't have a line for this day of the week.\n" unless $found1;
- X die "$0: No one is assigned to be on duty at this time.\n" if $w eq '-';
- X
- X # Now search until a line begins with $w= and assign line to wholist
- X $opt_wholist = '';
- X while (<SCHED>) {
- X next unless /^${w}\=/;
- X chop( $opt_wholist = substr($_, 2) );
- X }
- X die "$0: Schedule error: No people assigned to '" . $w . "'\n" unless $opt_wholist;
- X close SCHED;
- X}
- X
- X####################################################################
- X# we we still don't know who to call, bail out.
- X
- die "$0: The schedule didn't specify anyone to call!"
- X unless ($opt_wholist) || ($opt_d && $opt_p);
- die "$0: There isn't anyone scheduled for this time of day."
- X if $opt_wholist eq '-';
- X
- X####################################################################
- X# rotate through "$opt_wholist" and queue each person
- X
- X$cnt = 0;
- foreach $who ( split(',', $opt_wholist) ) {
- X $cnt++;
- X
- X # look up "who"'s information
- X open(TABL, "<$opt_T") || die "Can't open $opt_T: $!";
- X while (<TABL>) {
- X next if /^#/;
- X chop;
- X local($name,$phonen,$phonea,$pin) = split;
- X if ($name eq $who) {
- X $opt_d = $phonea unless $opt_d; # might have it from ARGV
- X $opt_p = $pin unless $opt_p; # might have it from ARGV
- X print "Got $who is :$opt_d:$opt_p:\n" if $debug;
- X last;
- X }
- X }
- X close TABL;
- X
- X die "$0: We were not able to find a phone number for $who.\n" unless $opt_d;
- X die "$0: We were not able to find a PIN for $who.\n" unless $opt_p;
- X
- X # write into the queue the proper information.
- X chop( $thishost = `hostname` );
- X $qname = $QUEUE_DIR . "P" . $thishost . time . $cnt;
- X print "QUEUE=$qname\n" if $debug;
- X open(QU, ">$qname" ) || die "Can't open $qname for writing: $!";
- X print QU "A\n";
- X print QU $opt_d, "\n";
- X print QU $opt_p, "\n";
- X if ($opt_e eq '-') { # '-' means send errors to $who,
- X print QU $who, "\n";
- X } else {
- X print QU $opt_e, "\n";
- X }
- X print QU $the_message, "\n";
- X print QU "X\n";
- X close QU;
- X print "Message queued for $who: $the_message\n";
- X
- X # zap the phone# and PIN so that ARGV's info only effects us once.
- X $opt_d = "";
- X $opt_p = "";
- X}
- X
- print "\n";
- END_OF_FILE
- if test 9757 -ne `wc -c <'tpage.pl'`; then
- echo shar: \"'tpage.pl'\" unpacked with wrong size!
- fi
- chmod +x 'tpage.pl'
- # end of 'tpage.pl'
- fi
- if test -f 'tpaged.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tpaged.pl'\"
- else
- echo shar: Extracting \"'tpaged.pl'\" \(8441 characters\)
- sed "s/^X//" >'tpaged.pl' <<'END_OF_FILE'
- X#! /usr/local/bin/perl4.019
- X
- X# tpaged -- back-end to tpage system.
- X# by Tom Limoncelli, tal@warren.mentorg.com
- X# Copyright (c) 1992, Tom Limoncelli
- X# The sources can be freely copied for non-commercial use only
- X# and only if they are unmodified.
- X
- X# Version 1.0 -- See file HISTORY for details.
- X
- X####################################################################
- X#
- X# Parameters that the user can set:
- X#
- X####################################################################
- X
- X$debug = 0;
- X$QUEUE_DIR = '/home/adm/lib/tpage/pqueue/'; # same as in tpage.pl
- X$IXOCICO = '/home/tal/work/beep2/ixocico'; # where is ixocico?
- X$MAIL = '/usr/ucb/mail'; # which mail to use?
- X
- X# list of devices to rotate through.
- X@DEVICES = ( "/dev/ttyz4" ); # currently they are all spoken
- X# to at the same speed and same parameters. Some day I'll set up
- X# a modemtab system, but I don't think more than one modem is
- X# really needed for this system.
- X
- X# amount of time to sleep between scans
- X$SLEEP_TIME = 30;
- X
- X####################################################################
- X# QUEUE FILES FORMAT:
- X#
- X# Files in the queue have the name of the format in the
- X# first line. Currently there is only one format and it
- X# is named "A". The first line marks it as the "A" format.
- X# a subroutine called read_format_A reads this format. Other
- X# formats can be written (see comments by read_format_A)
- X#
- X# The "A" format:
- X# line contents
- X# 1: A\n
- X# 2: number to dial\n
- X# 3: pin\n
- X# 4: entire message\n
- X# 5: X\n
- X
- X# read_format_* -- modules that read various data formats.
- X# Currently implemented: The "A" format.
- X# do_proto_* -- modules that do various beeper protocols.
- X# Currently implmented: the ixo protocol.
- X# Future protocols: numeric-only pagers.
- X
- X####################################################################
- X# Here's the actual program
- X
- X# define some globals
- X
- local(%ixo_dial);
- local(%protocols);
- X
- while (1) {
- X local ($first,$allfiles);
- X
- X # We could scoop up all the files and process them, but chances
- X # are if one file is found, more are on the way. So, instead
- X # we scoop, if any are found we sleep 5 seconds and re-scoop.
- X while (1) {
- X opendir(QDIR, $QUEUE_DIR) || die "$0: Can't open $QUEUE_DIR: $!";
- X @allfiles = grep( !/^\./, readdir(QDIR) );
- X closedir(QDIR);
- X
- X if ($#allfiles!=-1) { # files? take 5 and then process.
- X sleep 5;
- X last;
- X } else { # no files? hibernate.
- X sleep $SLEEP_TIME;
- X next;
- X }
- X }
- X
- X print "DEBUG: allfiles= ", join(' ', @allfiles), "\n" if $debug;
- X opendir(QDIR, $QUEUE_DIR) || die "$0: Can't open $QUEUE_DIR: $!";
- X @allfiles = grep( !/^\./, readdir(QDIR) );
- X closedir(QDIR);
- X print "DEBUG: allfiles= ", join(' ', @allfiles), "\n" if $debug;
- X
- X foreach $file (@allfiles) {
- X print "DEBUG: Doing $file\n" if $debug;
- X open(DATA, "<" . $QUEUE_DIR . $file) || print "Can't open $file: $!";
- X chop( $first = <DATA> );
- print "DEBUG: first=$first\n" if $debug;
- X eval "do read_format_$first();";
- X }
- X
- X foreach $proto (sort keys %protocol) {
- X next unless $protocol{ $proto };
- X eval "do do_protocol_$proto();";
- X $protocol{ $proto } = 0;
- X sleep $SLEEP_TIME;
- X }
- X}
- X
- X# Each read_format_ must:
- X# read from <DATA> and then close(DATA).
- X# %protocol{ protocol name } = 1 (for the protocol to use)
- X# and stuff the right data into the right variables for that protocol
- X# to use.
- X
- sub read_format_A
- X{
- X local($dial,$pin,$error,$mess,$X);
- X print "DEBUG: reading format A\n" if $debug;
- X chop( $dial = <DATA> );
- X chop( $pin = <DATA> );
- X chop( $error = <DATA> );
- X chop( $mess = <DATA> );
- X chop( $X = <DATA> );
- X
- X return if $X ne "X"; # file isn't in correct format or isn't done.
- X return if $dial eq "";
- X return if $pin eq "";
- X return if $mess eq "";
- X
- X $protocol{ 'ixo' } = 1;
- X $ixo_dial{ $dial } = 1;
- X eval "unshift(@ixo_${dial}_pin, \$pin)";
- X eval "unshift(@ixo_${dial}_error, \$error)";
- X eval "unshift(@ixo_${dial}_mess, \$mess)";
- X eval "unshift(@ixo_${dial}_file, \$file)";
- X}
- X
- X# Each do_protocol_ must:
- X# delete files out of the queue that are successful.
- X# delete files out of the queue that are aged.
- X# clean up so that the routine can be called again.
- X
- sub do_protocol_ixo {
- X print "DEBUG: doing protocol IXO\n" if $debug;
- X# local($pin, $error, $mess, $file, $cmd, $empty);
- X local($pin, $error, $mess, $file, $cmd);
- X# $empty = 1;
- X # build the temp file and the command line
- X local($tmpfile) = "/tmp/tpaged.$$";
- X foreach $dial (keys %ixo_dial) {
- X next unless $ixo_dial{ $dial };
- X print "DEBUG: Number to dial is $dial\n" if $debug;
- X open(IX, ">$tmpfile" ) || die "$0: Can't create $tmpfile: $!";
- X foreach (eval "@ixo_${dial}_pin") {
- X print IX eval "pop(@ixo_${dial}_pin )", "\n";
- X print IX eval "pop(@ixo_${dial}_mess)", "\n";
- X unshift(@ixo_list, eval "pop(@ixo_${dial}_error)" );
- X unshift(@ixo_list, eval "pop(@ixo_${dial}_file )" );
- X# $empty = 0;
- X }
- X close IX;
- X print "DEBUG: ", ($#ixo_list) / 2, " messages to send.\n" if $debug;
- X# if ($empty) {
- X# print "DEBUG: nothing to do!\n" if $debug;
- X# unlink $tmpfile;
- X# return;
- X# }
- X $cmd = $IXOCICO . " <" . $tmpfile . " "
- X . push(@DEVICES, shift @DEVICES) . " " . $dial;
- X print "DEBUG: About to execute: $cmd\n" if $debug;
- X open(IX, $cmd . "|") || die "$0: Can't execute ixocico: $!";
- X $mesgnum = 0; # count the messages as they're processed
- X $success = 0;
- X # get to the next message (same as #MESOK)
- X $error = pop(@ixo_list);
- X $file = pop(@ixo_list);
- X print "DEBUG: ERROR=$error; FILE=$file\n" if $debug;
- X while (<IX>) {
- X print if $debug;
- X next unless /^#/;
- X
- X print unless $debug;
- X
- X /^#WRONGARGS / &&
- X die("$0: Major program bug: $!");
- X /^#NOCONN / && do {
- X printf("$0: Nobody answered the phone!\n") if $debug;
- X last;
- X };
- X /^#UNKNOWNPROTO / && do {
- X print "$0: Uhhh, are you sure that's a pager service?\n" if $debug;
- X last;
- X };
- X /^\#MESOK (\d) / && do {
- X print "DEBUG: message $1 done.\n" if $debug;
- X if ($1 == $mesgnum++) {
- X print "DEBUG: unlinking " . $QUEUE_DIR . $file . "\n" if $debug;
- X unlink $QUEUE_DIR . $file;
- X # get to the next message (same as #MESREJECT)
- X $error = pop(@ixo_list);
- X $file = pop(@ixo_list);
- X print "DEBUG: ERROR=$error; FILE=$file\n" if $debug;
- X } else {
- X print "Things have gotten out of sync. Restarting.\n" if $debug;
- X last;
- X }
- X };
- X /^#MESREJECT (\d) / && do {
- X if ($1 == $mesgnum++) {
- X if ($error) {
- X $cmd = "$MAIL <" . $QUEUE_DIR . $file . " -s 'the following pin and message was rejected' " . $error;
- X print "DEBUG: About to execute $cmd\n" if $debug;
- X }
- X print "DEBUG: unlinking " . $QUEUE_DIR . $file . "\n" if $debug;
- X unlink $QUEUE_DIR . $file;
- X # get to the next message (same as #MESOK)
- X $error = pop(@ixo_list);
- X $file = pop(@ixo_list);
- X print "DEBUG: ERROR=$error; FILE=$file\n" if $debug;
- X } else {
- X print "Things have gotten out of sync. Restarting.\n" if $debug;
- X last;
- X }
- X };
- X /^#FORDIS / && do {
- X print "Forced disconnect from server.\n" if $debug;
- X last;
- X };
- X /^#PROTERR / && do {
- X print "Server not following protocol.\n" if $debug;
- X last;
- X };
- X ( /^#DONE / || /#BYE / ) && do {
- X if ($#ixo_list) {
- X print "Done with sending batch. Waiting BYE.\n" if $debug;
- X $success = 1;
- X next;
- X } else {
- X print "ixocico is done but more data waiting to be sent! Program bug.\n" if $debug;
- X last;
- X }
- X };
- X /^#WRONGANY / && do {
- X print "We've been notified that one of the batch may have been not xmited.\n(great protocol, eh?)\n" if $debug;
- X next;
- X };
- X /^#BADQUEUE / && do {
- X die "$0: Programmer error. Data in queue is bad: $_\n";
- X };
- X /^#MODOPEN / && do {
- X print "Modem can't be opened\n" if $debug;
- X last;
- X };
- X /^#PACKLEN / && do {
- X die "$0: Protocol error. Should never happen: $_\n";
- X };
- X /^#GOTMESSEQ / && do {
- X print "MESSAGE: $_\n" if $debug;
- X };
- X /^#LONELY / && do {
- X print "Hello? Hello? Either I'm getting the silent treatment or the server is dead." if $debug;
- X last;
- X };
- X }
- X close IX;
- X unlink $tmpfile;
- X $ixo_dial{ $dial } = 0;
- X }
- X
- X print "DEBUG: ixo_dial = " if $debug;
- X foreach $i (keys %ixo_dial) {
- X next unless $ixo_dial{ $dial };
- X print $i if $debug;
- X };
- X print "\n" if $debug;
- X
- X eval "@ixo_${dial}_pin = ()";
- X eval "@ixo_${dial}_mess = ()";
- X eval "@ixo_${dial}_error = ()";
- X eval "@ixo_${dial}_file = ()";
- X $ixo_list = ();
- X}
- END_OF_FILE
- if test 8441 -ne `wc -c <'tpaged.pl'`; then
- echo shar: \"'tpaged.pl'\" unpacked with wrong size!
- fi
- chmod +x 'tpaged.pl'
- # end of 'tpaged.pl'
- fi
- echo shar: End of shell archive.
- exit 0
-