fyl@ssc.UUCP (Phil Hughes) (11/15/89)
This is a less than wonderful kludge to talk to EasyLink. I wrote in years ago for a PDP-11 under venix and made it work on too many other machines. The most valuable comment I have is, if you have UNIX and have a choice, get attmail. It works and understands uucp. EasyLink is a disaster to talk to from a machine. Anyway, have fun with this. It used to work. Phil Hughes, SSC, Inc. P.O. Box 55549, Seattle, WA 98155 (206)FOR-UNIX fyl@ssc or uunet!pilchuck!ssc!fyl or attmail!ssc!fyl -------------------- cut and/or mutilate here ---------------------- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # Makefile # README # abrev.c # commsub.c # easy.1 # easy.c # ecdef.h # ecomm.1 # ecomm.c sed 's/^X//' << 'SHAR_EOF' > Makefile X# following define for debug printouts X# CFLAGS=-DDEBUG -DSYS3 XCFLAGS=-DSYS3 # fixes for Plexus sys3 X X# where to user usable executables go XP = /u/local X# where to library type things go XL = /u/local/lib X Xall: easy ecomm X Xeasy: easy.o abrev.o X cc -o easy easy.o abrev.o X Xecomm: ecomm.o commsub.o X cc -o ecomm ecomm.o commsub.o X# cc -o ecomm ecomm.o commsub.o -lstr -lstr X Xeasy.o ecomm.o: ecdef.h X Xprint: Makefile ecdef.h abrev.c commsub.c easy.c ecomm.c X pr $? | lp X Xinstall: easy ecomm X cp easy $P X cp ecomm $L X chown root $P/easy X chown root $L/ecomm X chgrp ssc $P/easy X chgrp ssc $L/ecomm X chmod 6550 $P/easy X chmod 6550 $L/ecomm X Xman: easy.1 ecomm.1 X nroff -man -e -Tnecs $? |lp -dshady X Xclean: X rm *.bak *.o easy ecomm SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > README XThis is a less than wonderful kludge to talk to EasyLink. I wrote in Xyears ago for a PDP-11 under venix and made it work on too many other Xmachines. X XThe most valuable comment I have is, if you have UNIX and have a choice, Xget attmail. It works and understands uucp. EasyLink is a disaster to Xtalk to from a machine. X XAnyway, have fun with this. It used to work. X X XPhil Hughes, SSC, Inc. P.O. Box 55549, Seattle, WA 98155 (206)FOR-UNIX X fyl@ssc or uunet!pilchuck!ssc!fyl or attmail!ssc!fyl X SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > abrev.c X/* abrev.c -- abbreviation routine for easylink addresses X Version 1.1A 07-11-85 ph X*/ X X#include <stdio.h> X#include "ecdef.h" X X X Xstruct abtab /* abbreviation to actual conversion structure */ X { X char *abr; /* abbreviation */ X char *act; /* actual address */ X }; X Xstatic struct abtab lookup[] = X { X {"almac", "9104442067"}, X {"lansdale", "846373"}, X {"systech", "714990507(SYSTC)"}, X {"us", "62755801"}, X {NULL, NULL} X }; X X X X X X Xabrev(key) /* translate abbreviation into real address and output */ Xchar *key; /* key to look up in abbreviation table */ X { X struct abtab *pl = lookup; X X X while(pl->abr) X { X if (strcmp(key, pl->abr) == 0) X { X fputs(pl->act, stdout); X putchar(ADDEND); X putchar('\r'); X return 1; X } X pl++; X } X return 0; /* abbreviation not found */ X } SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > commsub.c X/* commsub.c -- communications subroutines X Version 1.6B 02-12-86 X V1.6: attempt to cover any possible holes like buffer X overflows for no particular reason X V1.5: added HUH mode to log all input and out messages X*/ X#include <stdio.h> X#include <fcntl.h> X#include <ctype.h> X#include "ecdef.h" Xunsigned sleep(); X X#ifdef HUH Xextern FILE *huhfp; X#endif X Xstatic char t1, t2; /* termination characters for rec */ Xstatic int port_fd = 0; /* port file descriptor */ X Xint initport(name, speed, tc1, tc2) /* initialize the port */ Xchar *name; /* pathname of port */ Xchar *speed; /* baud rate and any other funny characteristics */ Xchar tc1, tc2; /* termination characters for receive */ X { X char buf[80]; X#ifdef SSC X int stat; X#endif X X t1 = tc1; /* save termination characters */ X t2 = tc2; X#ifdef SSC X if (stat = system("/usr/local/originate")) X return stat; X#endif X if ((port_fd = open(name, O_RDWR | O_NDELAY)) < 0) X return 0; /* open failed */ X X#ifdef SYS3 X strcpy(buf,"stty <"); /* setup port characteristics */ X#else X strcpy(buf,"stty >"); /* setup port characteristics */ X#endif X strcat(buf, name); X strcat(buf, " raw -echo "); X strcat(buf, speed); X system(buf); X return port_fd; X } X X/* * * * * * * * * * * */ X Xint send(msg) /* send message */ Xchar *msg; X { X#ifdef DEBUG Xfprintf(stderr, "send(%s)", msg); X#endif X#ifdef HUH X fprintf(huhfp, "\ns> %s", msg); X#endif X return (write(port_fd, msg, (unsigned)strlen(msg))); X } X X/* * * * * * * * * * * */ X Xint rec(buffer, bufmax) /* receive message */ Xchar *buffer; /* receive buffer */ Xint bufmax; /* receive buffer size */ X /* waits for one line of input and returns it in caller's buffer X A line is terminated by either of the termination characters X specified in the initport call. The termination character X will appear as the last character in the buffer and a byte X count is returned. X Rec will also exit if bufmax characters have been received X or it has waited MAXWAIT seconds for an input string. In X either of these cases the character count is returned but X there is no null terminator appended to the message. X */ X { X int bc = 0; /* current count of chars received */ X int waits = 0; /* seconds we have waited for a message */ X char c; X X#ifdef DEBUG Xfprintf(stderr, "rec():"); X#endif X#ifdef HUH X fprintf(huhfp, "\nr> %s"); X#endif X do X { /* wait for a character */ X while (read(port_fd, &c, 1) == 0) X { X if (waits++ == MAXWAIT) X return bc; /* timeout */ X else X sleep(1); /* wait another second */ X } X c &= 0x7F; X if (c) /* toss out nulls */ X { X#ifdef DEBUG Xfputc(c, stderr); X#endif X#ifdef HUH X if (iscntrl(c) && c != '\n') X { X fputc('^', huhfp); X fputc(c | 0x40, huhfp); X } X else X fputc(c, huhfp); X#endif X X *buffer++ = c; X if (++bc >= bufmax) X return bc; /* buffer full */ X } X } X while (c != t1 && c != t2); X *buffer = '\0'; X return bc; /* real exit with good (terminated) message */ X } X Xendport() X { X close(port_fd); X#ifdef SSC X system("/usr/local/answer"); X#endif X } SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > easy.1 X.po 1i X.TH EASY 1L 02/14/86 X.SH NAME Xeasy \- queue output for EasyLink X.SH SYNOPSIS X\fB/usr/local/easy\fR [\fB-d\fR] X.SH DESCRIPTION X.LP XThis program is used to send messages via Western Union's EasyLink. XIt is possible to send messages to Telex, WorldWide Telex, EasyLink, XInfoCom and RediList stations as well as send Mailgrams, Telegrams and XCablegrams. X.LP XOnce invoked, \fBeasy\fR will prompt for the address. XThis should be entered on a line of its own. XSubsequent lines are assumed to be the text of the message and are Xcopied to the queue file until an end of file (^D) is encountered. X.LP XIf the first character of the address is a slash (/), \fBeasy\fR assumes Xthat a multiple line address follows and prompts with a statement Xto that effect. XFollow the address lines with a blank line the terminate the Xaddress entry mode. XThen just enter the message as you would normally. X.LP XOne additional feature is the abbreviated address mode. XWithin \fBeasy\fR (in module abrev.c) there is an address abbreviation Xtable. XIf the first character of the entered address is an at sign (@), easy Xlooks up the remainder of the line in the abbreviation table and Xuses what is found in the table as the actual address. X.LP XOnce the message is queued, \fBeasy\fR starts \fBecomm\fR, the program Xwhich actually sends messages to EasyLink and receives messages. XBefore terminating, \fBeasy\fR checks to see if you have any mail. X.LP XIf you do not want \fBecomm\fR to be activated, use the \fB-d\fR Xoption. XThe message will be queued but will not be sent until the next Xtime \fBecomm\fR is activated, either by another message being Xqueued without the \fB-d\fR option being initiated by cron. X.SH FILES X.nf X/usr/local/lib/ecomm EasyLink daemon program X/usr/spool/el/to_send outgoing message queue X/usr/spool/el/easy_lk message queue lock file X/usr/spool/uucp/LCK..tty6 port lock file X/dev/tty6 port to call EasyLink on X.fi X.SH "SEE ALSO" Xecomm(1L) SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > easy.c X/* easy.c -- easylink message queueing program X Version 1.5A Phil Hughes 11-27-84 X 1.5 add don't call immediately option (-d) X*/ X X#include <stdio.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <signal.h> X#include "ecdef.h" X Xchar *getlogin(); X Xchar lockfile[] = LOCKFILE; /* lock file for queue */ X X Xmain(argc, argv) Xint argc; Xchar *argv[]; X { X int fd_lock; /* fd for lock file */ X int status; X X if ((fd_lock = creat(lockfile,0)) == -1) /* get the queue lock */ X { X fputs("easy: EasyLink queue locked -- try later\n", stderr); X exit(1); X } X close(fd_lock); X if (freopen(QFNAME, "a", stdout) == 0) X { X fputs("easy: unable to open queue\n", stderr); X exit(1); X } X if (status = getaddr()) /* get destination addresses */ X { X cpmsg(); X fputs(EEOM, stdout); /* EOT to queue file */ X } X else X fputs("easy: Invalid address\n", stderr); X X fclose(stdout); /* close queue file */ X if (status && !(argc > 1 && !strcmp(argv[1], "-d"))) X stecomm(); /* start ecomm */ X else X unlink(LOCKFILE); X if(chkmail()) /* check for mail */ X fputs("You have mail\n", stderr); X exit(!status); X } X Xgetaddr() X { X char to[100], *pt = to; X X fputs("enter destination address:", stderr); X gets(pt); X if (*pt == '@') /* abbreviated address */ X { X if (abrev(++pt) == 0) /* bad address */ X return 0; X else X return 1; X } X else if (*pt == '/') /* multi-line address */ X { X fputs(to, stdout); X fputs("terminate the address with a blank line\n", stderr); X do X { X putchar('\r'); X gets(pt); X fputs(pt, stdout); X } X while(*pt != '\0'); X } X /* regular address or end of multi-line address */ X fputs(pt,stdout); X putchar(ADDEND); X putchar('\r'); X return 1; X } X Xcpmsg() /* copy message to queue */ X { X char buf[100]; X X while (gets(buf) != 0) X { X fputs(buf, stdout); X putchar('\r'); X } X } X Xstecomm() X { X int pid; X int fd_port; /* for uucp like port lock */ X X if ((fd_port = creat(LOCK_PORT, PORT_LK_MODE)) < 0) X { /* port in use -- quit */ X unlink(LOCKFILE); X return; X } X if ((pid = fork()) < 0) X punt(); X if (pid > 0) /* we are the parent */ X return; /* finish up */ X else X { X signal(SIGHUP, SIG_IGN); /* ignore hangups */ X close(fd_port); /* close port lock file and continue */ X execl(ECOMM, 0); /* become the spooler */ X punt(); X } X } X Xchkmail() X { X char *lname; /* pointer to login name */ X X if ((lname = getlogin()) != 0) X { X char mailbox[100]; X struct stat sbf; X struct stat *stbuf = &sbf; X X strcpy(mailbox, MAILDIR); /* directory */ X strcat(mailbox, lname); /* user name */ X if ((stat(mailbox, stbuf) == 0) && X (stbuf->st_size != 0)) X return 1; /* have mail */ X else X return 0; /* no mail */ X } X } X Xpunt() /* die */ X { X unlink(lockfile); X perror("easy: unable to start spooler"); X exit(errno); X } SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > ecdef.h X/* ecdef.h -- def file for EasyLink electronic mail system X Phil Hughes 10-12-84 X Plexus mods 2-12-86 ph X change MAXWAIT fro 5 to 10 so termination doesn't time out X 3-6-86 ph X Change modem port ph 10-26-87 X Change modem port again ph 2-24-88 X 386 changes 7-7-89 ph X */ X X X#define ADDLIST "/usr/local/lib/el.addresses" /* easylink address file */ X#define ECOMM "/usr/local/lib/ecomm" /* spooler program */ X#define QFNAME "/usr/spool/el/to_send" /* send queue */ X#define MSGFILE "/usr/spool/el/msgfile" /* temporary message file */ X#define MAILDIR "/usr/mail/" X#define LOCKFILE "/usr/spool/el/easy_lk" /* lock file for queue */ X#define PORT_LK_MODE 0444 X X#define ADDEND '+' /* address field terminator */ X#define PORT "/dev/tty3f" /* dial out port */ X#define LOCK_PORT "/usr/spool/uucp/LCK..tty3f" /* uucp like lock file name */ X#define DIAGOUT "/dev/console" /* where ecomm should send errors */ X#define CTL_Q 0x11 /* go ahead from easylink */ X#define CR 0x0D X#define EEOM "LLLL\r" /* easylink EOM */ X#define EEOT "MMMM\r" /* easylink EOT */ X#define ESMSG "/BATCH\r" /* easylink send messages */ X#define ERMSG "/MBX\r" /* easylink receive messages */ X#define SIGNOFF "/QUIT\r" /* easylink signoff */ X#define TO_DELIVER "mail jorg <" /* how to deliver mail */ X#define TELNO "\rATTD382-0910,,,120120\r" /* how to place call */ X#define SIGNON "00 xxxxxxxxx yyyyyyyyyyyy\r" /* signon sequence */ X#define SPEED " EXTA " /* stty stuff for port open */ X#define MAXWAIT 10 /* secs to wait for input message */ X Xextern int errno; SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > ecomm.1 X.po 1i X.TH ECOMM 1L 02/14/86 X.SH NAME Xecomm \- communications daemon for EasyLink X.SH SYNOPSIS X\fB/usr/local/lib/ecomm\fR X.SH DESCRIPTION X.LP XThis program communicates via Western Union's EasyLink. XIt is generally involed by \fBeasy\fR and processes the message queue Xfor EasyLink. XOnce it connects to EasyLink it also requests any queued messages for Xour EasyLink mailbox and forwards those messages via mail. X.SH FILES X.nf X/usr/spool/el/to_send outgoing message queue X/usr/spool/el/easy_lk message queue lock file X/usr/spool/el/msgfile temporary message file X/usr/spool/uucp/LCK..tty6 port lock file X/dev/console where to send error messages X/dev/tty6 port to call EasyLink on X.fi X.SH "SEE ALSO" Xeasy(1L) SHAR_EOF sed 's/^X//' << 'SHAR_EOF' > ecomm.c X/* ecomm.c -- easylink spooler program X V1.8B and define NEVER X V1.8A change strings.h to string.h 3-11-87 ph X Version 1.7A Phil Hughes 03-06-86 X V1.7: add wait in sendout for an extra 5 secs for el to respond X V1.6: compatability changes for new rec with second parameter X V1.5: add option to log and print all that transpired X in order to figure out what the $#%@#@$ happened. X Turn on with #define HUH X V1.4 feature: if called with argc != 0, it locks both X the message Q and uucp lock file itself. If either X fails, ecomm dies silently. X*/ X#define HUH X#define NEVER X X#include <stdio.h> X#include <string.h> X#include <fcntl.h> X#include <signal.h> X#include "ecdef.h" X#define PROGRAM "ecomm: " Xint getout(); Xvoid exit(); Xlong lseek(); Xstatic int msg_fd; /* fd for temp receive message file */ X X#ifdef HUH Xstatic char huhlog[] = "/tmp/elhuhXXXXXX"; Xstatic char huhprint[40] = "lp -c -s \0"; XFILE *huhfp; X#endif X Xmain(argc) Xint argc; X { X X#ifndef DEBUG X freopen(DIAGOUT, "w", stderr); /* error message output */ X#endif X#ifdef HUH X { X int oldmask; X mktemp(huhlog); X oldmask = umask(0); X huhfp = fopen(huhlog, "w+"); X umask(oldmask); X if (huhfp == NULL) X { X fprintf(DIAGOUT, "ecomm: can't open %s\n", huhlog); X exit(errno); X } X fprintf(huhfp, "\n****** ECOMM LOG ******\n\n"); X } X#endif X signal(SIGINT, getout); X if (argc != 0) X do_locks(); X if ((msg_fd = creat(MSGFILE, 0600)) < 0) X punt("unable to open message file"); X if (initport(PORT, SPEED, CTL_Q, CR) < 0) X punt("unable to open port"); X if (!call()) X punt("unable to call"); X if (!signon()) X punt("unable to sign on to EasyLink"); X#ifdef HUH X fprintf(huhfp, ">>> getmsg() \n"); X#endif X getmsg(); X#ifdef HUH X fprintf(huhfp, ">>> sendout() \n"); X#endif X sendout(); /* send outgoing messages */ X unlink(LOCKFILE); /* release queue lock */ X#ifdef HUH X fprintf(huhfp, ">>> signoff() \n"); X#endif X signoff(); X endport(); X unlink(LOCK_PORT); /* release port lock */ X deliver(); /* deliver messages as mail */ X if (unlink(MSGFILE)) X punt("unable to delete temporary message file"); X#ifdef HUH X fprintf(huhfp, "\n>>> ALL DONE! \n"); X fclose(huhfp); X system(strcat(huhprint, huhlog)); X unlink(huhlog); X#endif X } X X/*********************************************************************/ X Xgetout() /* ungraceful exit routine */ X { X endport(); X unlink(LOCK_PORT); X#ifdef HUH X fprintf(huhfp, "\n>>> I HAVE BEEN SHOT!!!\n"); X close(huhfp); X system(strcat(huhprint, huhlog)); X#endif X } X X/*********************************************************************/ X Xint call() /* place call */ X { X char buf[100]; X int msglen; X int try; X X send(TELNO); /* dial easy-link */ X sleep(15); /* wait for an answer -- KLUDGE */ X for (try = 0; try < 8; try++) X { X msglen = rec(buf, sizeof(buf)); X if (msglen && buf[msglen-1] == CTL_Q) X return 1; /* EasyLink is waiting for login */ X } X return 0; X } X Xint signon() /* send signon to EasyLink */ X { X char buf[100]; X X send(SIGNON); X do X { X rec(buf, sizeof(buf)); X } X while (!strfind(buf, "PTS")); /* wait for PTS */ X waitel(); /* wait for ready from easylink */ X return 1; X } X Xint getmsg() /* receive any messages out there */ X { X char buf[100]; X unsigned length; X int msgsize = 0; X X send(ERMSG); /* request messages */ X while(1) X { X length = rec(buf, sizeof(buf)); X if (!length || buf[length-1] == CTL_Q) X break; X if (write(msg_fd, buf, length) != length) X { X endport(); X punt("message file write error"); X } X msgsize += length; X } X close(msg_fd); X return msgsize; X } X Xsendout() /* send out queued messages */ X { X int out_fd; /* fd for file of messages to send */ X char buf[100]; X int stat; X X if ((out_fd = open(QFNAME, O_RDWR)) < 0) X return; /* assume nothing to send out */ X if ((stat = read(out_fd, buf, sizeof(buf)-1)) > 4) /* got a msg */ X { X send(ESMSG); /* get easylink ready */ X /* change last EOM to EOT */ X lseek(out_fd, -(long) strlen(EEOT), 2); X if (write(out_fd, EEOT, (unsigned)strlen(EEOT)) != strlen(EEOT)) X punt("unable to update queue file"); X lseek(out_fd, 0L, 0); /* re-position to start */ X while ((stat = read(out_fd, buf, sizeof(buf)-1)) > 0) X { X buf[stat] = '\0'; X send(buf); X } X sleep(5); /* wait for el to figure things out */ X waitel(); /* wait for easylink to be ready */ X } X close(out_fd); /* close queue file */ X if (unlink(QFNAME)) X gripe("unable to delete queue file"); X } X X Xsignoff() X { X send(SIGNOFF); X } X Xdeliver() /* deliver messages to unix user somehow */ X { X char buf[80]; X X strcpy(buf, TO_DELIVER); /* how to deliver */ X strcat(buf, MSGFILE); /* where to get messages */ X if (system(buf)) /* deliver them */ X punt("unable to deliver messages"); X } X Xpunt(msg) /* roll up and die */ Xchar *msg; X { X gripe(msg); X exit(errno? errno : 200); X } X Xgripe(msg) /* just complain */ Xchar *msg; X { X fputs(PROGRAM, stderr); X fputs(msg, stderr); X fputc('\n', stderr); X } X Xwaitel() /* wait for easylink to be waiting for us */ X { X char buffer[100]; X int msglen; X do X { X msglen = rec(buffer, sizeof(buffer)); X } X while (msglen && buffer[msglen-1] != CTL_Q); X } X Xdo_locks() /* lock Q and uucp lock -- die silently if I can't */ X { X int fd; X X if ((fd = creat(LOCKFILE, 0)) == -1) /* message Q lock */ X exit(0); X close(fd); X X if ((fd = creat(LOCK_PORT, PORT_LK_MODE)) < 0) /* port lock */ X { X unlink(LOCKFILE); /* release Q lock */ X exit(0); X } X close(fd); X } X X X#ifdef NEVER X/* X** STRFIND - find second string included in first X** Passed: first string X** second string X** Return: TRUE if second string included in first X*/ X Xstrfind(pa, str) X register char *pa; X char *str; X { X register char *pb, *pc, *pd; X X for (; *pa; pa++) X { X pb = pa; X pc = str; X while (*pc) X { X if (*pb++ != *pc) X break; X pc++; X } X if (*pc == '\0') X break; X } X return !*pc; X } X#endif SHAR_EOF -- Phil Hughes, SSC, Inc. P.O. Box 55549, Seattle, WA 98155 (206)FOR-UNIX amc-gw!ssc!fyl or uunet!pilchuck!ssc!fyl or attmail!ssc!fyl