home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Unix System Administration Handbook 1997 October
/
usah_oct97.iso
/
goodies
/
tap.txt
(
.txt
)
< prev
next >
Wrap
Microsoft Windows Help File Content
|
1995-05-03
|
20KB
|
710 lines
: This is a shar archive. Extract with sh, not csh.
echo x - Makefile
cat > Makefile << '!Funky!Stuff!'
CC= cc
CCFLAGS= -g
all: testmain pagemail
pagemail: tap.h tap.o io.o misc.o lock.o pagemail.o
$(CC) $(CCFLAGS) -o pagemail tap.o io.o misc.o lock.o pagemail.o
testmain: tap.h tap.o io.o misc.o lock.o testmain.o
$(CC) $(CCFLAGS) -o testmain tap.o io.o misc.o lock.o testmain.o
# Dependencies
tap.o: tap.c tap.h
io.o: io.c tap.h
misc.o: misc.c tap.h
lock.o: lock.c tap.h
!Funky!Stuff!
echo x - tap.h
cat > tap.h << '!Funky!Stuff!'
* defines and globals for the tap subroutines
#define DEBUG 1
#define LOCKDIR "/var/spool/locks"
#define PAGER "/etc/pagedata"
#define MAXPAGE 2048 /* maximum message length */
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <errno.h>
#include <sysexits.h>
#include <sys/termios.h>
#include <sys/types.h>
#include <sys/time.h> /* required for <sys/resource.h> */
#include <sys/resource.h> /* required for getpriority() */
/* ASCII constants */
#define STX 0x02
#define ETX 0x03
#define EOT 0x04
#define ACK 0x06
#define LF 0x0A
#define CR 0x0D
#define NAK 0x15
#define ESC 0x1B
#define RS 0x1E
/* this trick makes easy work of global variables */
#ifndef GLOBAL
#define GLOBAL
#endif
GLOBAL int modem; /* the modem device */
GLOBAL char mdmdev[32]; /* the modem device name */
GLOBAL char lockname[256]; /* the rooted modem lock file name */
GLOBAL char mdmbuf[4096]; /* what the modem saw */
GLOBAL char *mdm;
!Funky!Stuff!
echo x - io.c
cat > io.c << '!Funky!Stuff!'
#define GLOBAL extern
#include "tap.h"
* read a character from the modem. If there is an I/O error,
* return -1. If it times out, return 0. Else return the char
* timeout is in seconds; 0 = poll
getmdmchar(timeout)
int timeout;
char c[2];
fd_set readfd;
struct timeval tm;
int rslt;
if (DEBUG)
printf("getmdmchar(%d) ", timeout);
fflush(stdout);
recall:
FD_ZERO(&readfd);
FD_SET(modem, &readfd);
tm.tv_usec = 0;
tm.tv_sec = timeout;
rslt = select(20, &readfd, NULL, NULL, &tm);
if (rslt < 0)
if (errno == EINTR)
goto recall;
return(-1);
if (rslt == 0) /* timed out */
if (DEBUG)
puts("read timed out");
return(0);
if (!FD_ISSET(modem, &readfd))
return(-1);
if (DEBUG)
printf("got ");
/* so get the char already */
if (read(modem, c, 1) != 1)
perror("modem read");
return(-1);
c[0] &= 0x7f; /* toss input parity if any */
if ((mdm - mdmbuf) < sizeof(mdmbuf))
*mdm++ = c[0];
*mdm = 0;
if (DEBUG)
safechar(c[0]);
puts("");
fflush(stdout);
return(c[0]);
* send a string to the modem, one char at a time, and wait for each
* character to be echoed by the modem before you send the next one
* prevents outspeeding modem
* returns 0 if string is sent ok, +1 if it times out before the char
* echoes, -1 if there is an I/O problem
echosend(str)
char *str;
char c;
if (DEBUG)
printf("echosend: ");
/* what we saw */
mdm = mdmbuf;
*mdm = 0;
while (*str)
/* squirt out ONE character */
if (DEBUG)
safechar(*str);
if (write(modem, str, 1) != 1)
perror("echosend write");
return(-1);
/* get its echo if it's printable*/
while(isprint(*str))
c = getmdmchar(1);
if (c == 0)
return(1);
if (c == *str)
break;
/* spin until we get the echo */
/* got it, send the next one */
str++;
if (DEBUG)
puts("end echosend");
return(0);
/* open the modem */
opendev()
struct termios ti;
int err;
modem = open(mdmdev, (O_RDWR|O_EXCL), 0);
if (modem < 0)
perror(mdmdev);
return(errno);
if (DEBUG)
printf("%s is open on fd %d\n", mdmdev, modem);
/* get current port settings */
err = ioctl(modem, TCGETS, &ti);
if (err < 0)
perror(mdmdev);
return(errno);
* set tty params to 300bps, even parity, 7/E/1
* this is for SunOS 4.1.3. God help you on other systems.
ti.c_iflag |= IGNBRK; /* ignore breaks */
ti.c_iflag &= ~INPCK; /* ignore parity errors */
ti.c_iflag |= ISTRIP; /* strip 8th bit */
ti.c_iflag &= ~INLCR; /* don't cr->nl */
ti.c_iflag &= ~ICRNL; /* don't cr->nl */
ti.c_iflag &= ~IGNCR; /* don't ignore cr */
ti.c_oflag &= ~OPOST; /* don't process output */
ti.c_cflag &= ~CBAUD;
ti.c_cflag |= B300; /* baud=300 */
ti.c_cflag &= ~CSIZE; /* 7-bit bytes */
ti.c_cflag |= CS7;
ti.c_cflag &= ~CSTOPB; /* one stop bit */
ti.c_cflag |= PARENB; /* parity */
ti.c_cflag &= ~PARODD; /* even parity */
ti.c_cflag |= HUPCL; /* hang up on last close */
ti.c_cc[VMIN] = 1; /* read() can return 1 byte */
ti.c_cc[VTIME] = 0; /* no time out */
ti.c_lflag &= ~ISIG; /* disable signals */
ti.c_lflag &= ~ICANON; /* disable signals */
ti.c_lflag &= ~ECHO; /* don't echo */
errno = 0;
err = ioctl(modem, TCSETS, &ti);
if (err < 0)
perror(mdmdev);
return(errno);
return 0;
/* hang up the modem */
void
hangup()
sleep(3);
write(modem, "+++", 3);
sleep(3);
write(modem, "ATH\r", 4);
sleep(1);
write(modem, "ATZ\r", 4);
* swallows all characters from the modem until none for n seconds
swallow(n)
int n;
while (getmdmchar(n) > 0)
!Funky!Stuff!
echo x - lock.c
cat > lock.c << '!Funky!Stuff!'
#define GLOBAL extern
#include "tap.h"
* unlock the modem's tty port
unlockdev()
unlink(lockname);
* lock the modem's tty port
lockdev()
int lock, pid;
int fails = 5;
sprintf(lockname, "%s/LCK..%s", LOCKDIR, (rindex(mdmdev, '/')+1));
if (DEBUG)
printf("lock file = %s\n", lockname);
tryagain:
/* try to lock the modem a few times */
lock = open(lockname, (O_CREAT|O_RDWR|O_EXCL), 0666);
if (lock < 0)
if (errno != EEXIST) /* lock file problem */
perror("can't create modem lock file ");
return(EX_OSFILE);
/* see if it's a dead lock */
pid = 0;
lock = open(lockname, (O_CREAT|O_RDWR), 0666);
if (lock >= 0)
(void)read(lock, &pid, sizeof(int));
if (DEBUG)
printf("locked; pid %d\n", pid);
/* is he still there? */
errno = 0;
(void)kill(pid, 0);
if (errno != ESRCH) /* live pid */
{
close(lock);
if (fails--) /* try a few times */
{
sleep(30);
goto tryagain;
}
/* couldn't get modem, tempfail, try later */
printf("modem line %s not available\n", mdmdev);
return(EX_TEMPFAIL);
}
if (DEBUG)
puts("lock is stale");
/* we lock it for us! */
pid = getpid();
lseek(lock, 0L, 0);
write(lock, &pid, sizeof(int));
close(lock);
if (DEBUG)
printf("we locked line to pid %d\n", pid);
return(0);
!Funky!Stuff!
echo x - misc.c
cat > misc.c << '!Funky!Stuff!'
#define GLOBAL extern
#include "tap.h"
* crunch extra blanks out of a line of text
deblank(str)
char *str;
char *p;
/* tabs become spaces */
while ((p = index(str, '\t')))
*p = ' ';
/* leading spaces */
p = str;
while (*p && *p == ' ')
p++;
if (p != str)
strcpy(str, p);
/* trailing spaces */
p = str + (strlen(p) - 1);
while(p > str && *p == ' ')
*p-- = 0;
/* imbedded multiple strings */
p = str;
while ((p = index(p, ' ')))
if (*(p+1) == ' ')
strcpy(p, p+1);
else
p++;
/* print a character interpreting unprintable charactors */
void
safechar(c)
char c;
if (isprint(c))
(void)printf("`%c' ", c);
else
switch(c)
case LF:
(void)printf("`\\n' ");
break;
case CR:
(void)printf("`\\r' ");
break;
case '\t':
(void)printf("`^I' ");
break;
default:
(void)printf("0x%02x ", c);
break;
/* print a string interpreting unprintable charactors */
void
safeprint(str)
char *str;
if (str == NULL)
return;
while (*str)
safechar(*str++);
fflush(stdout);
/* calculate checksum of a packet */
char *checksum(str)
char *str;
static char csum[10];
int sum = 0;
for (; *str; str++)
sum += *str;
csum[2] = '0' + (sum & 0x0f);
sum = sum >> 4;
csum[1] = '0' + (sum & 0x0f);
sum = sum >> 4;
csum[0] = '0' + (sum & 0x0f);
csum[3] = 0;
if (DEBUG)
printf("checksum=%s\n", csum);
return(csum);
* expect a string from the modem - we assume it'll end in CR/LF
* and do the appropriate thing
* input: an array of pointers to strings that are matched.
* returns -1 if I/O error, 0 if timeout, n+1 if matched, -2 if no match
* (timeout means we didn't get CR or LF before time expired)
* ignores blank lines from the modem
expect(str, timeout)
char **str;
int timeout;
int i, rslt;
char *p;
again:
mdm = mdmbuf;
*mdm = 0;
for(;;)
rslt = getmdmchar(timeout);
if (rslt <= 0)
if (DEBUG)
printf("expect returns %d\n", rslt);
return(rslt);
if (rslt == '\r' || rslt == '\n')
break;
/* ignore blank lines from the modem */
if (strlen(mdmbuf) == 1 && (mdmbuf[0] == '\n' || mdmbuf[0] == '\r'))
goto again;
* mdmbuf contains the null-terminated string of what we rec'd.
* just search through all the strings until we find a match
if (DEBUG)
printf("modem returned ");
safeprint(mdmbuf);
puts("");
for (i=0; str[i]; i++)
if (DEBUG)
printf("find [%d]", i+1);
safeprint(str[i]);
puts("");
if (strstr(mdmbuf, str[i]))
if (DEBUG)
printf("expect returns %d\n", i+1);
return(i+1);
if (DEBUG)
puts("expect: no match (-2)");
return(-2);
!Funky!Stuff!
echo x - pagemail.c
cat > pagemail.c << '!Funky!Stuff!'
* sendmail backend program for sending e-mail to pagers
* Brian Kantor, UCSD, May 1994
* username is the only argument
* expects to find the username, device, phone#, and pin in '/etc/pager'
#include "tap.h"
FILE *pager;
int main(argc, argv)
int argc;
char *argv[];
int rslt, found;
char buf[BUFSIZ];
char usr[64];
char dev[64];
char tel[64];
char pin[64];
/* check arguments */
if (argc != 2)
fprintf(stderr, "Usage: %s username\n", argv[0]);
exit(EX_USAGE);
* open the pager database file
pager = fopen(PAGER, "r");
if (pager == NULL)
perror(PAGER);
exit(EX_UNAVAILABLE);
* search the pager database file for the user
found = 0;
while (fgets(buf, sizeof(buf), pager))
if (buf[0] == '#') /* skip comments */
continue;
rslt = sscanf(buf, "%s %s %s %s", usr, dev, tel, pin);
if (rslt != 4) /* bad entry */
fprintf(stderr, "error in %s entry\n", PAGER);
exit(EX_OSFILE);
if (strcasecmp(usr, argv[1]) == 0) /* found him! */
found++;
break;
if (!found)
fprintf(stderr, "Paging user '%s' not on file\n", argv[1]);
exit(EX_NOUSER);
rslt = tap(dev, tel, pin);
exit(rslt);
!Funky!Stuff!
echo x - tap.c
cat > tap.c << '!Funky!Stuff!'
* given a modem device name, a telephone number, a pager pin,
* and an RFC-822-compliant message to be read from infile,
* locks and opens the modem device, dials the number, and
* sends the first 2k or so of the mail to the pager.
* Brian Kantor, UCSD, May 1994
* some of the ideas taken from 'tpage', but almost all of the code
* is mine.
* 'dev' must be of the form "/dev/cua0", and expects a Hayes-type modem
* the terminal I/O is set up for SunOS 4.1.3. If you have something
* else, you're probably going to have to hack it.
#define GLOBAL extern
#include "tap.h"
* modem dialing result strings
static char *dialing[] = { /* 'expect' returns */
"CONNECT", /* 1 */
"BUSY", /* 2 */
"NO DIAL TONE", /* 3 */
"VOICE", /* 4 */
"NO CARRIER", /* 5 */
NULL };
* protocol responses
static char *proto[] = { /* 'expect' returns */
"ID=", /* 1 */
"\033\004", /* 2, ESC EOT */
"\033[p", /* 3, ESC [p (go ahead) */
"\006", /* 4, ACK */
"\025", /* 5, NAK */
"\036", /* 6, RS */
"\004", /* 7, EOT */
NULL };
tap(dev, telno, pin)
char *dev, *telno, *pin;
char pagebuf[MAXPAGE];
char buf[BUFSIZ];
char mesg[256];
char from[256];
char subj[256];
char word[256];
int failcnt, len;
int err;
char c;
char *m, *p;
* Read through the mail message to grab the From: address
* and the subject line
strcpy(from, "unknown");
strcpy(subj, "");
/* we're in the mail message header now */
while (fgets(buf, sizeof(buf), stdin))
p = index(buf, '\n'); if (p) *p = 0; /* elide EOL */
if (strlen(buf) < 1) /* empty line is end of header */
break;
deblank(buf);
if (strncasecmp(buf, "From: ", 6) == 0)
sprintf(from, "Fm: %s", buf+6);
if (strncasecmp(buf, "Subject: ", 9) == 0)
sprintf(subj, "[Sb: %s]", buf+9);
deblank(from);
strcpy(pagebuf, from);
strcat(pagebuf, " ");
deblank(subj);
if (strlen(subj))
strcat(pagebuf, subj);
strcat(pagebuf, " ");
/* we're in the mail message body now */
while (fgets(buf, sizeof(buf), stdin))
p = index(buf, '\n'); if (p) *p = 0; /* elide EOL */
deblank(buf);
strcat(pagebuf, buf);
strcat(pagebuf, " ");
if (strlen(pagebuf) > MAXPAGE)
break;
if (DEBUG)
puts(pagebuf);
* all done with the incoming message
* we now have the message in 'pagebuf', proceed to page
/* can we have the modem? */
err = lockdev();
if (err != 0)
return(err);
/* we've got it reserved, open it */
err = opendev();
if (err != 0)
unlockdev();
return(err);
/* just in case it's off-hook for some reason */
hangup();
mdm = mdmbuf;
*mdm = 0;
/* flush any garbage in the rx queue */
swallow(1);
(void)echosend("\r\r"); /* terminate any partial command */
swallow(1);
/* Ok, at this point, the modem should be ready and waiting */
err = 5; /* try 5 times to speed sense the modem */
while (err && echosend("A") == 1)
err--;
if (err == 0) /* it didn't wake up */
unlockdev();
return(EX_TEMPFAIL);
swallow(1);
/* send the dialstring */
sprintf(buf, "ATDT %s \r", telno);
if (echosend(buf)) /* couldn't dial the modem */
unlockdev();
return(EX_TEMPFAIL);
err = expect(dialing, 60);
if (err != 1)
fprintf(stderr, "calling error #%d\n", err);
hangup();
unlockdev();
return(EX_IOERR);
/* ----------------------------------------------------
* connected, start the TAP protocol dance.
* ---------------------------------------------------- */
if (DEBUG)
printf("Waiting for ID=\n");
failcnt = 0;
for (;;)
if (failcnt > 3)
hangup();
unlockdev();
fprintf(stderr, "unable to sync with central\n");
return(EX_TEMPFAIL);
err = expect(proto, 2);
if (err == 0) /* timeout, send a CR and wait again */
write(modem, "\r", 1);
continue;
if (err == 1) /* got ID= */
break;
/* something else went wrong */
hangup();
unlockdev();
return(EX_TEMPFAIL);
if (DEBUG)
printf("Logging in\n");
failcnt = 0;
login:
/* switch to "automatic protocol" */
printf("Sending ESC, termtype, and password\n");
write(modem, "\033", 1);
/* send our terminal type */
write(modem, "PG1", 3);
/* alphanumeric password */
write(modem, "000000\r", 7);
/* see what response we get to our login attempt */
err = expect(proto, 60);
if (err == 0) /* timeout */
hangup();
unlockdev();
fprintf(stderr, "no response from central\n");
return(EX_TEMPFAIL);
/* if our login failed, we might have got ID= or NAK again */
if (err == 1 || err == 5)
failcnt++;
if (failcnt > 3)
hangup();
unlockdev();
fprintf(stderr, "unable to log in to central\n");
return(EX_TEMPFAIL);
goto login;
if (err == 2) /* ESC EOT = disconnect now */
hangup();
unlockdev();
fprintf(stderr, "central demanded disconnect\n");
return(EX_TEMPFAIL);
if (err != 4) /* ACK = proceed */
hangup();
unlockdev();
fprintf(stderr, "unknown response from central: %s\n", mdmbuf);
return(EX_TEMPFAIL);
* Hah! We're in!
* wait for them to stop spewing and give us the go-ahead
processing:
err = expect(proto, 30);
if (err == 0) /* timeout */
hangup();
unlockdev();
fprintf(stderr, "no response from central\n");
return(EX_TEMPFAIL);
/* absorb any irrelevant spew */
if (err == -2) /* nothing we care about */
goto processing;
if (err != 3) /* not a go-ahead */
hangup();
unlockdev();
fprintf(stderr, "unknown response from central: %s\n", mdmbuf);
return(EX_TEMPFAIL);
* loop through here until you've sent it all
* you have to break the message into pieces about 230 chars
m = pagebuf;
p = word;
*p = 0;
* copy the message into 220 character pieces,
* one word at a time, breaking at whitespace
while (*m)
while (*m)
if (!isspace(*m))
{
*p++ = *m++;
*p = 0;
continue;
}
m++;
if (DEBUG)
printf("word '%s'\n", word);
/* long enough? */
if ((strlen(mesg) + strlen(word)) > 220)
break;
strcat(mesg, word);
p = word;
*p = 0;
strcat(mesg, " ");
if (DEBUG)
printf("mesg '%s'\n", mesg);
failcnt = 0;
blockagain:
sprintf(buf, "%c%s\r%s\r%c", STX, pin, mesg, ETX);
strcat(buf, checksum(buf));
strcat(buf, "\r");
if (DEBUG)
printf("send packet (length %d): ", strlen(buf));
safeprint(buf);
puts("");
write(modem, buf, strlen(buf));
err = expect(proto, 30);
if (err == 0) /* timeout */
hangup();
unlockdev();
fprintf(stderr, "no response from central\n");
return(EX_TEMPFAIL);
if (err == 5) /* NAK, send block again */
failcnt++;
if (failcnt > 3)
{
hangup();
unlockdev();
fprintf(stderr, "excessive retransmits\n");
return(EX_TEMPFAIL);
}
goto blockagain;
if (err != 4) /* not an ACK */
hangup();
unlockdev();
fprintf(stderr, "error from central: %s\n", mdmbuf);
return(EX_TEMPFAIL);
/* all done with message, tell them so. */
if (DEBUG)
printf("send EOT at end of message\n");
write(modem, "\004\r", 2);
/* wait for them to finish spewing */
err = expect(proto, 30);
if (err == 0 || err == 2 || err == 7) /* timeout, disc, EOT */
hangup();
unlockdev();
puts(mdmbuf); /* in case rcpt-to */
return(EX_OK); /* message got through, so it's ok */
/* hmm. If we got here, we got some late error. Fail! */
hangup();
unlockdev();
fprintf(stderr, "late error from central: %s\n", mdmbuf);
return(EX_UNAVAILABLE);
!Funky!Stuff!
echo x - testmain.c
cat > testmain.c << '!Funky!Stuff!'
#define GLOBAL
#include "tap.h"
int main(argc, argv)
int argc;
char *argv[];
int rslt;
/* check arguments */
if (argc != 3)
fprintf(stderr, "Usage: %s device telno pin\n", argv[0]);
exit(EX_USAGE);
rslt = tap(argv[1], argv[2], argv[3]);
fprintf(stderr, "\ntap(%s, %s, %s) returned %d\n",
argv[1], argv[2], argv[3], rslt);
exit(rslt);
!Funky!Stuff!
echo x - test.sh
cat > test.sh << '!Funky!Stuff!'
testmain /dev/cua0 82328425 19620 < testmsg
!Funky!Stuff!
echo x - testmsg
cat > testmsg << '!Funky!Stuff!'
From: pagertest@my.local.host
Subject: test message
I have seen potatoes you people wouldn't believe.
Attack tractors on fire off the shoulder of Clare.
I watched spuds glitter in the dark near the farmhouse gate.
All those moments will be lost in time, like tears in the rain.
Time to eat. - jslttery@GS150.SP.CS.CMU.EDU
catnip is a kitty cat drug
one puff two puffs -- high in a dream
funny kitty's got very sleepy eyes
i wonder what he's dreaming of
catnip dream catnip dream catnip dream
meow meow meow
- shonen knife
!Funky!Stuff!