Path: utzoo!attcan!uunet!cs.utexas.edu!sun-barr!apple!netcom!ward From: ward@netcom.UUCP (Mike Ward) Newsgroups: comp.os.minix Subject: XCOMM 2.2 for MINIX v1.3d (part 3) Keywords: terminal emulation, xmodem, cisb, phonelist, script Message-ID: <1275@netcom.UUCP> Date: 23 May 89 13:37:34 GMT Organization: NetCom Services - Public Access Unix System (408) 997-9175 guest Lines: 2301 Greetings ... I was looking around for a communications program to use under MINIX V1.3 and found XCOMM 2.2 by Larry Gensch on the COMPUSERVE UNIX forum. It took a little hacking to get it to run properly under MINIX, and I haven't tested everything thouroughly, but the things I have tried seem to work, so I though it would be safe to post. (Please send me info on any problems you find). MINIX XCOMM 2.2 supports the XMODEM file transfer protocol with CRC or CHECKSUM error detection, CompuServe Information Service protocol B, text capturing, and a phone directory. It also comes with documentation (which I've updated to reflect the changes I made), and should be fairly compatable with XCOMM 2.2 which Larry will support. I'm posting the package in three shell archives. Enjoy ... cut below the dotted line and place it in a file (xc22pX.sh) and then run through the MINIX v1.3 shell: sh xc22pX.sh ------------------------------------------------------------------------------- echo x - readme sed '/^X/s///' > readme << '/' XXCOMM 2.2 MINIX: X XNew in this release... X X* Modified XCOMM command line interface X* CIS "Quick B" Protocol support for faster up/downloads X* Brand new script processor with integration into the phonebook X* Some code cleanup X* Better "vanilla" Unix support (thanks to bug reports) X XRefer to "historical.doc" for a list of ALL new features. X XXCOMM is a PUBLIC DOMAIN (not shareware) communication program that works on XUnix System V.3 (and MINIX). It probably works on other Unix systems with no Xmodification, since no machine specific coding was done. X XMINIX XCOMM is distributed in three bundles: X XXCM22P1.SH All documentation for XCOMM XXCM22P2.SH source code, header files, and makefile. XXCM22P3.SH source code X XThis README manifest file is included in both packages. X XContents of XCM22P1.SH: X Xreadme This manifest file Xscript.doc Quick reference to the XCOMM script language Xxcomm.doc Latest documentation for the XCOMM program Xhistorical.doc Historical information about versions 1.0 and 1.1 Xphonelist.doc Documentation on using XCOMM's phonelist X X XContents of XCM22SRC.SH: X Xreadme This manifest file Xinstall.doc Quick installation notes Xmakefile Make file for compiling XCOMM Xcis.cmd A sample XCOMM script file for logging onto CompuServe. X.phonelist A sample Phone List file Xxcomm.h XCOMM's header file Xxcxmdm.c XCOMM XMODEM protocol module Xxccisb.c XCOMM CIS-B/QuickB protocol module X X XContents of XCM22SRC.SH: X Xreadme This manifest file Xxcomm.c XCOMM main program Xxcport.c XCOMM Terminal I/O module Xxcscrpt.c XCOMM Script processor Xxcsubs.c XCOMM's subroutines Xxcterm.c XCOMM Terminal mode module / echo x - xcomm.c sed '/^X/s///' > xcomm.c << '/' X/* X xcomm External (and XMODEM) Communications X By Eric E. Coe X X Version 2.0 and above by larry gensch, ESQ X (modified for MINIX by mike ward) X X This program is in the public domain, and anyone can use it for X personal or non-profit use. Feel free to study the code and borrow X from it (I borrowed from other programs to create it). X X I am supporting versions 2.0 and higher of XCOMM. Information (bug X fixes, requests, etc.) may be sent to any one of the following electronic X addresses: X X CompuServe [72236,3516] UNIXFORUM X Delphi LARRYG X Bix lar3ry X Andover CNode (BBS) [617-470-2548] larry gensch X X -lar3ry gensch X programmer extraordinaire X X*/ X X#define VERSION "2.2" X X/* X R E V I S I O N H I S T O R Y X XVersion 2.2 MINIX mike ward 20 May 89 X Modified terminal mode special characters to IBM-PC ALT chars X Removed PUT_TAKE if defs and PUT_TAKE code X Removed HAVE_DUP2 if defs and DUP2 code X Removed HAVE_STRSTR if defs and STRSTR code X Removed DTR_DROPS_CARRIER if defs and associated code X Modified to use rather than however X XON/XOFF control is stubbed out since not controllable in RAW mode X Interruptability is not controllable in RAW mode X Removed text vs binary XMODEM transfers. Can only send/recieve XMODEM X one way. If you want to modify the file contents use a filter. X Modified open of /dev/tty to use w+, this required MINIX fopen mod X Removed reperences to getopt, opterr, optarg for command line args X Had to add fflush calls to get output to screen working in places X Had to shorten some external names to make them uniq in first 7/8 chars X s_set_* to ss_*, script_* to spt_* X Had to add code to define strdup X Added help message to terminal mode X Modified signal stuff since MINIX did not behave as expected X SIGALRM to SIGIOT X SIGUSR1 to SIGQUIT X SIGCLD to SIGHUP X added signal SIGHUP from child to parent on child termination X Modified erasln to use ^[[0K to erase to end of line X XVersion 2.2 larry gensch 12/8/87 Major code restructure X Reduced program and command options X Added SET command for setting various parameters X Added HANGUP command for disconnecting modem X Modified xccisb.c code to support CIS "Quick B" Protocol X Added xcscrpt.c code for processing script files X Added SCRIPT= parameter to phonebook processing (auto-logon scripts) X Added CIS parameter for CIS auto transfers X Added NL parameter for newline translation X Added HANGUP command from terminal mode X Added SCRIPT command from terminal mode X XVersion 2.1b larry gensch 11/11/87 Bug Fix release X (no bugs in the code, just some portability fixes) X Changed "sigset" in xccisb to "signal" X Removed #include from xcxmdm X XVersion 2.1a larry gensch 10/28/87 General Update X Added CIS "B" Protocol (c, ct commands) X Added BAUD= & BITS= parameters to phonelist file. X Switched some command letters X Revised command line parsing to use getopt() X XVersion 2.0 larry gensch 10/19/87 Revisions for System V.3 X Basically version 1.1 with minor modifications X XVersion 1.1 Eric E Coe 7/21/85 X Autodial for Hayes-compatible modem. X General rearranging of the code X XVersion 1.0 Eric E Coe 4/12/85 X Program created X*/ X X#include X#include X#include X#include X X#include "xcomm.h" X X/* globals */ X Xjmp_buf erret; /* non-local error return */ Xint mungmode = FALSE; /* ok to overwrite files? */ Xint nlmode = TRUE; /* Map newlines to carriage returns */ Xint stat_flag = FALSE; /* Flag for status display */ X X/* locals */ Xstruct sgttyb newbmode, oldbmode, sigbmode; Xstruct tchars newcmode, oldcmode, sigcmode; X Xstatic int termflag = 0; Xstatic int reterm = 0; X Xint tfd; XFILE *tfp; X Xvoid s_cis(), s_script(), s_xmodem(), s_set(), s_term(), s_exit(); Xvoid s_shell(), s_help(), hangup(); X X/* X Command table X*/ X Xstatic struct kw cmds[] = { X { "c", s_cis }, X { "g", s_script }, X { "hangup", hangup }, X { "xr", s_xmodem }, X { "xs", s_xmodem }, X { "set", s_set }, X { "t", s_term }, X { "x", s_exit }, X { "exit", s_exit }, X { "!", s_shell }, X { "!!", s_shell }, X { "$", s_shell }, X { "help", s_help }, X { "?", s_help }, X { NULL, NULL }}; X Xstatic char oldshell[WBSIZE]; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X extern char *optarg; X extern int optind, opterr; X X struct kw *ptr; X void catch(); X int i,c; X char *script = NULL; X X if ((tfp = fopen("/dev/tty", "w+")) == NULL) { X fprintf(stderr, "Cannot access local terminal!\n"); X exit(1); X } X X tfd = fileno(tfp); X X ioctl(tfd, TIOCGETP, &oldbmode); /* get current console tty mode */ X ioctl(tfd, TIOCGETC, &oldcmode); X ioctl(tfd, TIOCGETP, &newbmode); X ioctl(tfd, TIOCGETC, &newcmode); X ioctl(tfd, TIOCGETP, &sigbmode); X ioctl(tfd, TIOCGETC, &sigcmode); X X newbmode.sg_flags = (newbmode.sg_flags & 01700) | RAW | XTABS; X sigbmode.sg_flags = (sigbmode.sg_flags & 01700) | RAW | XTABS; X X nlmode = TRUE; X X oldshell[0] = '\0'; /* set last command to blank */ X reterm = FALSE; /* no direct jump into terminal mode */ X if(setjmp(erret)) /* set error handler to exit */ X exit(0); /* while parsing command line */ X signal(SIGINT, catch); /* catch break & quit signals/keys */ X signal(SIGQUIT, catch); X X for (i=1; i "); /* command prompt */ X X getsome(line); X intdel(0); X fprintf(tfp, "\r\n"); X fflush(tfp); X X getword(); X if (word[0] == '\0') /* If blank line... reprompt */ X continue; X X for (ptr = cmds; ptr->keyword != NULL; ptr++) X if (strcmp(word, ptr->keyword) == 0) X break; X X if (ptr->keyword) X (*ptr->rtn)(); X else X fprintf(tfp, "Unrecognized keyword: %s\r\n", word); X } X X} X Xstatic char *babble[] = { X"Usage: xcomm [-l device] [-t] [-g file]", X"", X"-l device Use 'device' as the modem port (eg, -l /dev/tty1)", X"-t Enter terminal mode immediately", X"-g file Execute script file 'file' immediately", X"", XNULL }; X Xusage() X{ X char **ptr; X X for (ptr = babble; *ptr != NULL; ptr++) X fprintf(stderr, "%s\r\n", *ptr); X} X Xvoid s_script() X{ X getword(); X X if (word[0] == '\0') { X fprintf(tfp, "Script file not specified\r\n"); X return; X } X X do_script(word); X reterm = 1; X} X Xvoid s_xmodem() X{ X char d = word[1]; X X getword(); X if (word[0] == '\0') X fprintf(tfp, "No transfer file specified\r\n"); X else if (d == 's') X xsend(); X else X xreceive(); X X reterm = termflag; X} X Xvoid s_exit() X{ X signal(SIGINT, SIG_IGN); X signal(SIGQUIT, SIG_IGN); X X do_exit(0); X} X Xvoid s_term() X{ X for (;;) { X terminal(); X if (cismode != 2) X return; X cismode = 1; X B_Transfer(); X } X} X Xvoid s_cis() X{ X B_Transfer(); X reterm = termflag; X} X Xvoid s_shell() X{ X char c = word[0]; X char *ptr; X static char *shell = NULL; X char *getenv(); X int child; X X if (word[0] == word[1]) X strcpy(wptr=word, oldshell); X else { X getword(); X if (*wptr) X strcpy(oldshell, wptr); X } X X if (!shell) { X shell = getenv("SHELL"); X if (!shell) X shell = "/bin/sh"; X } X X ioctl(tfd, TIOCSETP, &oldbmode); X ioctl(tfd, TIOCSETC, &oldcmode); X X if ((child = forkem()) == 0) { X if (c == '$') /* Attach modem to stdin, stdout */ X mattach(); X if (word[0] == '\0') X execl(shell, shell, "-i", (char *) NULL); X else X execl(shell, shell, "-c", wptr, (char *) NULL); X fprintf(stderr, "Exec failed!"); X exit(1); X } X X while (wait((int *) 0) != child) X ; X X intdel(0); X X strcpy(oldshell, wptr); X} X Xstatic char *cmdlist[] = { X"XCOMM Command Summary", X"c <-- Initiate CIS QuickB File Transfer (Upload and Download)", X"g file <-- Execute XCOMM Script file", X"xr file <-- XMODEM receive file", X"xs file... <-- XMODEM send file", X"set ... <-- XCOMM Parameter set", X"t <-- Enter terminal emulation", X"x <-- Exit program", X"! <-- Execute a local interactive shell", X"! cmd <-- Execute shell command string on the local system", X"!! <-- Re-execute the last shell command string", X"$ cmd <-- Shell command with stdin and stdout redirected to modem", X"? <-- Print this help message", X"", X"SET Keywords:", X"set Display current XCOMM status", X"set 7bit on|off Set/Reset 7-bit data mask (ignore high bits)", X"set crc on|off Enable/Disable Xmodem CRC", X"set term on|off Enable/Disable terminal mode after file transfer", X"set cis on|off Set/Reset CIS mode (Auto up/download)", X"set mung on|off Set/Reset file overwrite", X"set purge on|off Set/Reset bad phone line mode", X"set xoff on|off Set/Reset XON/XOFF flow control", X"set baud Set baud rate to ", X"set cfile name Change name of capture file", X"set pfile name Change name of phonelist file", XNULL }; X Xvoid s_help() X{ X char **ptr = cmdlist; X X for ( ; *ptr != NULL; ptr++) X if (**ptr) X fprintf(tfp, "%s\r\n", *ptr); X else { X fprintf(tfp, "PRESS ENTER: "); X getsome(line); X erasln(); X } X} X Xvoid ss_7bit(), ss_crc(), ss_term(), ss_cis(), ss_mung(), ss_cr(); Xvoid ss_purge(), ss_xoff(), ss_baud(), ss_cfile(), ss_pfile(); X Xstatic struct kw setlist[] = { X { "7bit", ss_7bit }, X { "nl", ss_cr }, X { "crc", ss_crc }, X { "term", ss_term }, X { "cis", ss_cis }, X { "mung", ss_mung }, X { "purge", ss_purge }, X { "xoff", ss_xoff }, X { "baud", ss_baud }, X { "cfile", ss_cfile }, X { "pfile", ss_pfile }, X { NULL, NULL }}; X Xvoid s_set() X{ X struct kw *ptr; X X getword(); X X if (word[0] == '\0' && !scriptflag) { X status(); X return; X } else if (word[0] == '\0') { X fprintf(tfp, "SET keyword requires an argument\r\n"); X eof_flag++; X return; X } X X lc_word(word); X X for (ptr = setlist; ptr->keyword != NULL; ptr++) X if (strcmp(ptr->keyword, word) == 0) { X (*ptr->rtn)(); X return; X } X X fprintf(tfp, "Invalid SET keyword: %s\r\n", word); X eof_flag++; X} X Xstatic char *statfmt = "%-8s %30s is %s\r\n"; X Xvoid ss_7bit() X{ X int val; X X if (stat_flag) { X fprintf(tfp, statfmt, "7bit", "Seven-bit Mask", X bitmask==0xff?"ON":"OFF"); X return; X } X X set_onoff(&val); X bitmask = val?0x7f:0xff; X X if (!scriptflag) X fprintf(tfp, "<<%s-bit mask enabled>>\r\n", val?"Seven":"Eight"); X} X Xvoid ss_crc() X{ X if (stat_flag) { X fprintf(tfp, statfmt, "crc", "Xmodem CRC", X crcheck?"ON":"OFF"); X return; X } X X set_onoff(&crcheck); X X if (!scriptflag) X fprintf(tfp, "<>\r\n", X crcheck?"CRC Check":"Checksum"); X} X Xvoid ss_cr() X{ X if (stat_flag) { X fprintf(tfp, statfmt, "nl", "Terminal NL Translation", X nlmode?"ON":"OFF"); X return; X } X X set_onoff(&nlmode); X if (!scriptflag) X fprintf(tfp, "<<%s mode enabled>>\r\n", X nlmode?"Newline translation":"Carriage return"); X} X Xvoid ss_term() X{ X if (stat_flag) { X fprintf(tfp, statfmt, "term", "Auto Term Mode", X termflag?"ON":"OFF"); X return; X } X X set_onoff(&termflag); X X if (!scriptflag) X fprintf(tfp, "<>\r\n", X termflag?"terminal":"command"); X} X Xvoid ss_cis() X{ X if (stat_flag) { X fprintf(tfp, statfmt, "cis", "CIS Auto Download", X cismode?"ON":"OFF"); X return; X } X X set_onoff(&cismode); X X if (!scriptflag) X fprintf(tfp, "< Auto Download is %s>>\r\n", X cismode?"ON":"OFF"); X} X Xvoid ss_mung() X{ X if (stat_flag) { X fprintf(tfp, statfmt, "mung", "File Overwrite", mungmode?"ON":"OFF"); X return; X } X X set_onoff(&mungmode); X X if (!scriptflag) X fprintf(tfp, "<>\r\n", mungmode?"ON":"OFF"); X} X Xvoid ss_purge() X{ X if (stat_flag) { X fprintf(tfp, statfmt, "purge", "Bad Telephone line", X badline?"ON":"OFF"); X return; X } X X set_onoff(&badline); X X if (!scriptflag) X fprintf(tfp,"<>\r\n",flowflag?"ON":"OFF"); X} X Xset_onoff(flag) X int *flag; X{ X char *strdup(); X char *ptr = strdup(word); X X getword(); X lc_word(word); X X if (strcmp(word, "on") == 0) { X *flag = 1; X } else if (strcmp(word, "off") == 0) { X *flag = 0; X } else { X fprintf(tfp, "Set '%s' value must be 'on' or 'off'.\r\n", ptr); X eof_flag++; X } X X free(ptr); X} X Xvoid ss_baud() X{ X if (stat_flag) { X char br[10]; X X sprintf(br, "%d", mbaud((char *) 0)); X fprintf(tfp, statfmt, "baud", "Baud Rate", br); X return; X } X X getword(); X if (word[0] == '\0') { X fprintf(tfp, "Set Baud must have a baud rate.\r\n"); X eof_flag++; X return; X } X X if (mbaud(word)<0) { X fprintf(tfp, "Unsupported baud rate %s\r\n", word); X eof_flag++; X } else if (!scriptflag) X fprintf(tfp, "<>\r\n", mbaud((char *) 0)); X} X Xvoid ss_cfile() X{ X if (stat_flag) { X fprintf(tfp, statfmt, "cfile", "Capture file", captfile); X return; X } X X getword(); X if (word[0] == '\0') { X fprintf(tfp, "Set CFILE must have file name.\r\n"); X eof_flag++; X return; X } X X strcpy(captfile, word); X X if (!scriptflag) X fprintf(tfp, "<>\r\n", captfile); X} X Xvoid ss_pfile() X{ X if (stat_flag) { X fprintf(tfp, statfmt, "pfile", "Phone number file", phonefile); X return; X } X X getword(); X if (word[0] == '\0') { X fprintf(tfp, "Set PFILE must have file name.\r\n"); X eof_flag++; X return; X } X X strcpy(phonefile, word); X X if (!scriptflag) X fprintf(tfp, "<>\r\n", phonefile); X} X X/* X * Catch a signal and jump to main. Reset signal and do a longjmp X */ Xvoid catch() X{ X fprintf(tfp,"\r\nXCOMM: Interrupt\r\n"); X X signal(SIGINT, catch); X signal(SIGQUIT, catch); X longjmp(erret, 1); X} X X/* X * Print the status of the program X */ Xstatus() X{ X struct kw *ptr; X void (*fct)() = NULL; X X stat_flag = 1; X X fprintf(tfp, "\fXCOMM Version %s by larry gensch - modem port: %s\r\n\n", X VERSION, mport((char *) NULL)); X fprintf(tfp, "Keyword Description and Status\r\n"); X fprintf(tfp, "------- ----------------------------------------------\r\n"); X X for (ptr = setlist; ptr->keyword != NULL; ptr++) X if (ptr->rtn != fct) { X fct = ptr->rtn; X (*fct)(); X } X X fprintf(tfp, "\r\n"); X stat_flag = 0; X} X Xdo_exit(rc) X{ X unlock_tty(); X X fprintf(tfp, "\r\n"); X X ioctl(tfd, TIOCSETP, &oldbmode); X ioctl(tfd, TIOCSETC, &oldcmode); X X fclose(tfp); X X exit(rc); X} X Xdo_startup() X{ X char *home, *getenv(); X char file[WBSIZE]; X X if (access(STARTUP, 0) == 0) X strcpy(file, STARTUP); X else { X if ((home = getenv("HOME")) == NULL) X return; X sprintf(file, "%s/%s", home, STARTUP); X if (access(file, 0)) X return; X } X X linkflag = 2; X do_script(file); X} / echo x - xcport.c sed '/^X/s///' > xcport.c << '/' X/* X * Module: xcport.c XCOMM Modem Interface Routines X * X * This code is purely public domain! X */ X X#include X#include X#include X#include X X#include "xcomm.h" X X/* X The dial() routine uses these two defines. X X DIALSTR is a sprintf format string that assumes a HAYES-compatible X modem. X X HAYSATT is the HAYES "attention" signal (used if DTR_DROPS_CARRIER X is not set to 1). X X HAYSHUP is the HAYES "hangup" command (used if DTR_DROPS_CARRIER is not X set to 1). X X MDELAY is the delay in the output because (on my modem) the command X would be ignored if sent at full speed. Change for other setups. X (This setting is for U.S. Robotics Password Modem). X*/ X X#define DIALSTR "\rATDT %s\r" /* format string for Hayes-type modem */ X#define HAYSATT "+++" /* Hayes "attention" signal */ X#define HAYSHUP "ATH\r" /* Hayes "hang up" command */ X#define MDELAY 20000 /* delay for output to modem itself */ X X/* globals */ X Xextern int tfp; /* TTY file pointer */ Xint bitmask = 0xFF; /* modem port i/o data mask */ Xint flowflag = 0; /* modem port i/o data mask */ X Xstatic int mfd = -1; /* modem port file descriptor */ Xstatic struct sgttyb pbmode; /* modem device control string */ Xstatic struct tchars pcmode; /* modem device control string */ Xstatic char port[NMSIZE]; /* modem port device file string */ Xstatic int baudrate = B1200; /* baud rate */ X Xint cpmode() X{ X pbmode.sg_flags = RAW | BITS8; X pbmode.sg_ispeed = baudrate; X pbmode.sg_ospeed = baudrate; X X xc_setflow(); X} X Xint xc_setxon(mode) X{ X cpmode(); X X if (mode) { X ; /* turn on XON/XOFF processing */ X } else { X ; /* turn off XON/XOFF processing */ X } X X if(mfd != -1) { X ioctl(mfd, TIOCSETP, &pbmode); X ioctl(mfd, TIOCSETC, &pcmode); X } X} X Xint xc_flowtoggle() X{ X flowflag = 1 - flowflag; X X xc_setflow(); X} X Xxc_setflow() X{ X if (flowflag) { X ; /* turn on XON/XOFF processing */ X } else { X ; /* turn off XON/XOFF processing */ X } X X if (mfd != -1) { X ioctl(mfd, TIOCSETP, &pbmode); X ioctl(mfd, TIOCSETC, &pcmode); X } X} X Xchar *mport(s) /* get/set port string */ Xchar *s; X{ X if(s != NULL && mfd == -1) X strcpy(port, s); X return(port); X} X X/* Get/set the baud rate of the modem port. If the port hasn't been opened yet, X * just store in pmode for mopen() to use when it opens the port. X */ Xint mbaud(s) Xchar *s; X{ X cpmode(); X X if(s != NULL){ X /* this gives a more limited, realistic range than in sgtty.h */ X switch (atoi(s)) { X case 300: baudrate = B300; break; X case 1200: baudrate = B1200; break; X case 2400: baudrate = B2400; break; X case 9600: baudrate = B9600; break; X default: return(-1); X } X pbmode.sg_flags &= ~BITS8; X pbmode.sg_ispeed = baudrate; X pbmode.sg_ospeed = baudrate; X X if(mfd != -1) { X ioctl(mfd, TIOCSETP, &pbmode); X ioctl(mfd, TIOCSETC, &pcmode); X } X } X X switch(pbmode.sg_ospeed){ X case B300: return(300); X case B1200: return(1200); X case B2400: return(2400); X case B9600: return(9600); X } X X fprintf(tfp,"Impossible error in baud rate.\n"); X return(0); X} X X/* X * The following routine is used to hang up the modem. This is X * accomplished by setting the baud rate to 0. According to my X * documentation on termio, setting the baud rate to zero will X * result in DTR not being asserted. This hangs up some (most?) X * modems. If not, the second part of the routine sends the Hayes X * modem "escape" and then a hangup command. X */ X Xvoid hangup() X{ X if (mfd == -1) X return; X X fprintf(tfp,"<< HANGUP >>\r\n"); X fflush(stdout); X X sleep(2); /* Allow for "escape guard time" */ X send_slowly(HAYSATT); /* Send modem escape command */ X X sleep(3); /* More "escape guard time" */ X send_slowly(HAYSHUP); /* Send hangup command */ X} X X/* Opens the modem port and configures it. If the port string is X * already defined it will use that as the modem port; otherwise it X * gets the environment variabele MODEM. Returns 0 for sucess X * or -1 on error. X */ X Xstatic int opened = 0; X Xint mopen() X{ X char *p, *getenv(); X X cpmode(); X X if(port[0] == '\0'){ X if((p = getenv("MODEM")) == NULL) X return(-1); X strcpy(port, p); X } X X if (lock_tty()) X return -1; X X if((mfd = open(port, O_RDWR)) < 0) X return -1; X X ioctl(mfd, TIOCSETP, &pbmode); X ioctl(mfd, TIOCSETC, &pcmode); X X opened++; X X return(0); X} X X/* Attach standard input and output to the modem port. This only gets called X * after a fork by the child process; which then exec's a program that uses X * standard i/o for some data transfer protocol. (To put this here is actually X * a kludge, but I wanted to keep the modem-specific stuff in a black box.) X */ Xmattach() /* attach standard i/o to port */ X{ X dup2(mfd, 0); /* close local stdin and connect to port */ X dup2(mfd, 1); /* close local stdout and connect to port */ X X close(mfd); /* close the old port descriptor */ X} X Xint readbyte(seconds) Xint seconds; X{ X return trminp(mfd, seconds); X} X X/* X * Read a byte using bitmask X */ X Xread_mbyte(secs) X{ X int c; X X return (c = readbyte(secs)) == -1 ? -1 : c & bitmask; X} X X/* Output a byte to the modem port. X * All data sent to the modem is output through this routine. X */ Xsendbyte(ch) Xint ch; X{ X char c = ch & 0xff; X X write(mfd, &c, 1); X} X Xsend_mbyte(ch) X{ X sendbyte(ch & bitmask); X} X X/* Dial a phone number, using proper format and delay. X */ X Xstatic char *last_nbr = NULL; Xchar *strdup(); X Xdial(s) Xchar *s; X{ X char buffer[WBSIZE]; X X if (last_nbr) X free(last_nbr); X X last_nbr = strdup(s); X X sprintf(buffer, DIALSTR, s); X send_slowly(buffer); X} X Xredial(s) X char *s; X{ X char *s; X X if (last_nbr == NULL) { X fprintf(tfp,"REDIAL FAILURE\r\n"); X return 1; X } X X s = strdup(last_nbr); X dial(s); X free(s); X return 0; X} X Xsend_slowly(s) X char *s; X{ X int i; X X/* X * This busy-waiting, normally a bad idea on a multi-tasking system, X * was used because sleep(1) is way too much of a delay. X */ X while(*s){ X send_mbyte(*s++); X for(i = 0; i < MDELAY; i++) X ; X } X} X X/* X * I have had requests to support the LCK..ttyxx files that CU and UUCP X * tend to support. I do not have any need for such code, and am not X * exactly sure how the code should work. I have therefore placed these X * two entry points for some enterprising coder to code so that the lock X * files may be created and destroyed. X * X * lock_tty() returns non-zero if the lock file exists (prevents XCOMM from X * running). X * X * unlock_tty() deletes the lock file. X * X * Simple, eh? X */ X Xlock_tty() X{ X return 0; X} X Xunlock_tty() X{ X} / echo x - xcscrpt.c sed '/^X/s///' > xcscrpt.c << '/' X/* X * Program xcscrpt.c Script handler for xcomm X * Author larry gensch, ESQ December 4, 1987 X * X * This code is released to the public domain X */ X X#include X#include X#include X X#include "xcomm.h" X X#define MAX_PATH 256 X#define MAX_LINE 128 X Xextern char *getenv(); Xextern FILE *tfp; X Xstatic FILE *spt_file, *cf; Xstatic int waitfor_time = 0; Xstatic int tty_flag = 1; Xstatic int echo_flag = 0; Xstatic int if_flag = 0; Xstatic int waitflag = 0; Xstatic int captflag = 0; Xstatic jmp_buf here; X Xstatic void k_waitfor(), k_transmit(), k_pause(), k_exit(), k_quit(); Xstatic void k_if(), k_goto(), k_else(), k_endif(), k_redial(); Xstatic void k_dial(), s_set(), hangup(), k_echo(), k_tty(), k_capture(); X X/* globals */ X Xint linkflag = 0; Xint scriptflag = 0; X Xstatic struct kw kw[] = { X { "waitfor", k_waitfor }, X { "transmit", k_transmit }, X { "pause", k_pause }, X { "exit", k_exit }, X { "if", k_if }, X { "else", k_else }, X { "endif", k_endif }, X { "hangup", hangup }, X { "goto", k_goto }, X { "dial", k_dial }, X { "redial", k_redial }, X { "quit", k_quit }, X { "set", s_set }, X { "echo", k_echo }, X { "capture", k_capture }, X { "tty", k_tty }, X { NULL, NULL }}; X Xstatic void newsigint(); X Xdo_script(file) X char *file; X{ X int quiet = 0; X X if (open_script(file)) { X fprintf(tfp, "Cannot find script file %s\r\n", file); X return; X } X X if (linkflag == 2) { X quiet = 1; X linkflag = 0; X } X X if (!quiet) { X fprintf(tfp, "<<< RUNNING SCRIPT >>>\r\n"); X fflush(tfp); X } X X if_flag = 0; X echo_flag = 0; X captflag = 0; X tty_flag = 1; X scriptflag = 1; X X if (setjmp(here) == 0) { X signal(SIGINT, newsigint); X intdel(1); X X for (eof_flag = 0; !eof_flag; ) X get_line(); X } X X fclose(spt_file); X if (captflag) X fclose(cf); X X if (!quiet) { X fprintf(tfp, "<< SCRIPT COMPLETE >>\r\n"); X fflush(tfp); X } X X linkflag = 0; X scriptflag = 0; X X signal(SIGINT, SIG_IGN); X intdel(0); X X return; X} X Xstatic void newsigint() X{ X signal(SIGINT, SIG_IGN); X X eof_flag = 1; X fprintf(tfp, "\r\nUser Abort...\r\n"); X fflush(tfp); X longjmp(here); X} X Xstatic char path[MAX_PATH]; X Xstatic open_script(file) X char *file; X{ X char *home; X X eof_flag = 0; X X if (spt_file = fopen(file, "r")) X return 0; X X if ((home = getenv("HOME")) == NULL) X return 1; X X sprintf(path, "%s/%s", home, file); X X if (spt_file = fopen(path, "r")) X return 0; X X return 1; X} X Xstatic char wf[MAX_LINE]; X Xstatic get_line() X{ X int i; X X getline(spt_file); X X if (eof_flag) X return; X X getword(); X lc_word(word); X X if (echo_flag) { X if (strcmp(word, "transmit")) X fprintf(tfp, "%s\r\n", line); X else X fprintf(tfp, "TRANSMIT...\r\n"); X fflush(tfp); X } X X if (word[0] == '\0') /* Ignore blank lines */ X return; X if (word[0] == '#') /* Ignore comments */ X return; X X if (word[strlen(word) - 1] == ':') /* Ignore labels */ X return; X X if (if_flag == -1) { X if (strcmp(word, "else") && strcmp(word, "endif")) X return; X } X X for (i = 0; kw[i].keyword != NULL; i++) X if (strcmp(kw[i].keyword, word) == 0) { X (*kw[i].rtn)(); X return; X } X X fprintf(tfp, "UNDEFINED COMMAND: \"%s\"\r\n", word); X fflush(tfp); X eof_flag = 1; X return; X} X Xstatic void k_waitfor() X{ X long t; X int c; X char *ptr = wf; X X quote_flag = 1; X getword(); X quote_flag = 0; X if (eof_flag) X return; X X if (word[0] == '\0') { X fprintf(tfp, "No argument to WAITFOR command\r\n"); X fflush(tfp); X eof_flag = 1; X return; X } X X strcpy(wf, word); X lc_word(wf); X X getword(); X if (eof_flag) X return; X X if (word[0]) X waitfor_time = atoi(word); X else X waitfor_time = 30; X X t = time(NULL) + waitfor_time; X X ptr = wf; X while (t != time(NULL) && !eof_flag) { X if ((c = read_mbyte(1)) == -1) X continue; X X if (tty_flag) X fputc(c, tfp); X X if (captflag) X fputc(c, cf); X X if (mklow(c) != *ptr) { X ptr = wf; X continue; X } X X if (*++ptr == '\0') { X waitflag = 1; X return; X } X } X X waitflag = 0; X} X Xstatic void k_transmit() X{ X char *ptr; X X quote_flag = 1; X getword(); X quote_flag = 0; X if (eof_flag) X return; X X if (word[0] == '\0') { X fprintf(tfp, "No argument to TRANSMIT command\r\n"); X fflush(tfp); X eof_flag = 1; X return; X } X X send_slowly(word); X} X Xstatic void k_pause() X{ X int pause_time; X X getword(); X if (eof_flag) X return; X X if (word[0] == '\0') X pause_time = 5; X else X pause_time = atoi(word); X X sleep(pause_time); X} X Xstatic void k_quit() X{ X do_exit(0); /* Terminate XCOMM */ X} X Xstatic void k_exit() X{ X eof_flag = 1; X} X Xstatic char label[WBSIZE]; X Xstatic void k_goto() X{ X int found = 0, i; X X getword(); X if (word[0] == '\0') { X fprintf(tfp, "No argument for GOTO: %s\r\n", line); X fflush(tfp); X eof_flag++; X return; X } X X strcpy(label, word); X lc_word(label); X X rewind(spt_file); X while (!found) { X getline(spt_file); X if (eof_flag) X break; X X getword(); X if (word[0] == '\0' || word[0] == '#') X continue; X X if (word[i = (strlen(word)-1)] != ':') X continue; X X word[i] = '\0'; X X lc_word(word); X found = (strcmp(word, label) == 0); X } X X if (eof_flag) { X fprintf(tfp, "Label %s not found\r\n", label); X fflush(tfp); X eof_flag++; X return; X } X X if_flag = 0; /* reset IF flag */ X} X Xstatic if_negate = 0; X Xstatic void k_if() X{ X char *ptr; X X if (if_flag) { X fprintf(tfp, "Nested IF statements not allowed\r\n"); X fflush(tfp); X eof_flag++; X return; X } X X if_negate = 0; X getword(); X if (word[0] == '\0') { X fprintf(tfp, "No condition on IF statement\r\n"); X fflush(tfp); X eof_flag++; X return; X } X X lc_word(word); X if (strcmp(word, "not") == 0) { X if_negate = 1; X getword(); X if (word[0] == '\0') { X fprintf(tfp, "No condition on IF statement\r\n"); X fflush(tfp); X eof_flag++; X return; X } X } X X if (word[0] == '!') { X if_negate = 1; X ptr = word + 1; X } else X ptr = word; X X if (strcmp(ptr, "waitfor") == 0) { X if_flag = if_test(waitflag); X return; X } X X if (strcmp(ptr, "linked") == 0) { X if_flag = if_test(linkflag); X return; X } X X fprintf(tfp, "Undefined IF condition %s\r\n", ptr); X fflush(tfp); X eof_flag++; X return; X} X Xstatic if_test(cond) X int cond; X{ X if (if_negate) X cond = !cond; X X if (cond) X return 1; X else X return -1; X} X Xstatic void k_else() X{ X if (!if_flag) { X fprintf(tfp, "ELSE not within IF\r\n"); X fflush(tfp); X eof_flag++; X return; X } X X if_flag = -if_flag; X} X Xstatic void k_endif() X{ X if (!if_flag) { X fprintf(tfp, "ENDIF not wihtin IF\r\n"); X fflush(tfp); X eof_flag++; X return; X } X X if_flag = 0; X} X Xstatic void k_dial() X{ X getword(); X X if (word[0] == '\0') { X fprintf(tfp, "DIAL command must have an argument\r\n"); X fflush(tfp); X eof_flag++; X return; X } X X dial(word); X} X Xstatic void k_redial() X{ X if (redial()) { X eof_flag++; X return; X } X} X Xstatic void k_echo() X{ X set_onoff(&echo_flag); X return; X} X Xstatic void k_capture() X{ X int val = captflag; X X set_onoff(&captflag); X if (eof_flag) X return; X X if (val == captflag) X return; X X if (captflag == 0) X fclose(cf); X else { X if ((cf = fopen(captfile, "a")) == NULL) { X fprintf(tfp, "Cannot open capture file %s\r\n"); X fflush(tfp); X eof_flag++; X return; X } X } X} X Xstatic void k_tty() X{ X set_onoff(&tty_flag); X return; X} X / echo x - xcsubs.c sed '/^X/s///' > xcsubs.c << '/' X/* X * Module: xcsubs.c XCOMM Subroutines X * X * Revisions: X * X * 2.2 lg Now uses /dev/tty instead of stdin/stdout X * 2.2 lg Added command parser X */ X X#include X#include X#include X#include X X#include "xcomm.h" X Xextern struct sgttyb newbmode, sigbmode; Xextern struct tchars newcmode, sigcmode; Xextern FILE *tfp; /* Local terminal */ Xextern int tfd; /* Local terminal */ X Xchar line[WBSIZE]; /* Input line */ Xchar word[WBSIZE]; /* Parsed word */ Xchar *wptr, *lptr; /* Word and line pointers */ Xint quote_flag = 0; /* Indicates special processing during parse */ Xint eof_flag = 0; /* Indicates EOF during getline() processing */ X Xchar *strdup(str) /* duplicate a string and return pointer to copy */ Xregister char *str; X{ X extern char *strcpy(),*malloc(); X char *new; X X if ((new = malloc(strlen(str))) != NULL) X strcpy(new,str); X return (new); X} X Xsendstr(p) /* send a string to the port */ Xregister char *p; X{ X while(*p) X send_mbyte(*p++); X} X X/* Do the fork call, packaging the error return so that the caller X * need not have code for it. X */ Xforkem() X{ X int i; X X if((i = fork()) < 0){ X fprintf(tfp,"XCOMM: Fork failed"); X longjmp(erret, 1); X } X return(i); X} X X/* Convert uppercase characters to lowercase, (without X * mangling non-uppercase characters), in a portable manner. X */ Xmklow(c) Xint c; X{ X if(isupper(c)) X return(tolower(c)); X return(c); X} X X/* This is an string input routine to be used X * when the raw terminal mode is in effect. X */ Xgetsome(s) Xchar *s; X{ X int c, i; X X if (s == line) { X lptr = line; X memset(line, 0, WBSIZE); X } X X i = 0; X while((c = coninp()) != '\r' && c != '\n') { X if(c == '\b'){ X if(i > 0){ X i--; X fprintf(tfp,"\b \b"); X } else X putc(7, tfp); X continue; X } X s[i++] = c; X putc(c, tfp); X } X s[i] = '\0'; X putc(' ', tfp); X} X X/* X * Erase current line without moving downwards X */ Xerasln() X{ X int i; X X fprintf(tfp,"\r\033[0K\r"); X fflush(tfp); X} X X/* X * Throw away all input characters until no more are sent. X */ Xpurge() X{ X while(readbyte(1) != -1) X ; X} X X/* X * Parse the "line" array for a word X */ Xgetword() X{ X char *ptr = word; X char quote = '\0'; X int bflag = 0, qflag = 0; X int c; X X *ptr = '\0'; X if (eof_flag || *lptr == '\0') X return; X X while (isspace(*lptr)) X lptr++; X X wptr = lptr; X X if (*lptr == '\0') X return; X X if (*lptr == '\'' || *lptr == '\"') X quote = *lptr++; X else X quote = '\0'; X X for (; *lptr != '\0'; lptr++) { X if (quote) { X if (*lptr == '\0') { X word[0] = '\0'; X fprintf(tfp, "Unmatched quote: %s\r\n", line); X eof_flag = 1; X return; X } X if (*lptr == quote) X break; X } else if (!qflag && isspace(*lptr)) X break; X X if (bflag) X *ptr++ = *lptr & 0x1f; X else if (qflag) X *ptr++ = *lptr; X else if (quote_flag && *lptr == '^') X bflag = 1; X else if (quote_flag && *lptr == '\\') X qflag = 1; X else X *ptr++ = *lptr; X } X X lptr++; X *ptr = '\0'; X} X X/* X * Make the specified word all lower case X */ Xlc_word(ptr) X char *ptr; X{ X while (*ptr) { X *ptr = mklow(*ptr); X ptr++; X } X} X X/* X * Input a line from the specified file X */ Xgetline(fp) X FILE *fp; X{ X int l; X X memset(line, 0, WBSIZE); X X if ((fgets((lptr=line), WBSIZE, fp)) == NULL) { X eof_flag = 1; X line[0] = '\0'; X } X X l = strlen(line); /* Purge newline if found */ X if (l--) { X if (line[l] == '\n') X line[l] = '\0'; X } X} X X/* X * trminp() is used as a single-character terminal input routine X */ Xstatic alrm() {} /* do nothing */ X Xint trminp(fd, seconds) Xint fd, seconds; X{ X static char rxbuf[BUFSIZ], *p; /* BUFSIZ is defined in stdio.h */ X static int count = 0; X X if(count > 0){ X count--; X return(*p++ & 0xff); X } X if(seconds > 0){ X signal(SIGALRM, alrm); X alarm((unsigned)seconds); X } X if((count = read(fd, p = rxbuf, BUFSIZ)) < 1) X return(-1); X if(seconds > 0) X alarm(0); X count--; X return(*p++ & 0xff); X} X X/* X * coninp() gets a single character from the local terminal X */ Xconinp() X{ X int c; X X fflush(tfp); X X while ((c = trminp(tfd, 0)) == -1) X ; X X return c; X} X Xintdel(flag) X{ X if (flag) { X ioctl(tfd, TIOCSETP, &sigbmode); X ioctl(tfd, TIOCSETC, &sigcmode); X } else { X ioctl(tfd, TIOCSETP, &newbmode); X ioctl(tfd, TIOCSETC, &newcmode); X } X} / echo x - xcterm.c sed '/^X/s///' > xcterm.c << '/' X/* xcterm.c XCOMM terminal mode X */ X X#include X#include X#include X#include X#include X#include "xcomm.h" X X/* globals */ Xchar captfile[NMSIZE] = CAPTFILE; /* capture file's name */ Xchar phonefile[NMSIZE] = PHFILE; /* phone number file's name */ Xint cismode = CIS_INIT; /* Respond to CIS "ENQ" */ Xextern FILE *tfp; /* Local terminal pointer */ X X/* locals */ Xstatic FILE *cfp; /* capture file pointer */ Xstatic int ctop; /* index top of capture buffer */ Xstatic int parent_pid = 0; /* ID of parent process */ Xstatic int child_pid = 0; /* ID of child process */ Xstatic int capture = FALSE; /* are we capturing or not ? */ Xstatic char *cbuffp = NULL; /* capture buffer pointer */ Xstatic jmp_buf rtm; Xstatic int frsttrm = 1; X X/* forward declarations */ Xvoid toggle(), cleanup(), newbmask(), cisbmode(); X Xstatic int spt_flag = 0; Xstatic char *spt_file; Xstatic char spt_buf[100]; X Xterminal() X{ X int c; X Xreterm: X setjmp(rtm); X X if (cismode > 1) X return; X X spt_flag = 0; /* reset scripting flag */ X parent_pid = getpid(); X X /* split into read and write processes */ X if((child_pid = forkem()) == 0){ X /* child, read proc: read from port and write to tty */ X cfp = NULL; X signal(SIGIOT, toggle); X signal(SIGTERM, cleanup); X signal(SIGQUIT, newbmask); X while(1){ X while((c = read_mbyte(0)) == -1) X ; X if (cismode && c == ENQ) { X cismode = 2; X cleanup(); X } X fputc(c, tfp); X fflush(tfp); X if(capture && c != '\r') X fputc(c, cfp); X } X /*NOTREACHED*/ X } X X /* parent, write proc: read from tty and write to port */ X signal(SIGHUP, cisbmode); X fprintf(tfp,"Entering Terminal Mode\r\n"); X if (frsttrm) { X termhelp(); X frsttrm = 0; X } X X do { X switch(c = coninp()) { X case TOGCHAR: /* signal child to toggle buffer */ X kill(child_pid, SIGIOT); X break; X X case DIVCHAR: /* divert a file through modem port */ X divert(); X break; X X case SCRPCHR: /* execute a script file */ X if (get_script()) X break; X spt_flag = 1; X goto fillicide; X X case PSELECT: /* select and dial a phone number */ X pselect(); X if (!spt_flag) X break; X X case ENDCHAR: /* signal child to cleanup and exit */ Xfillicide: X c = ENDCHAR; X signal(SIGHUP, SIG_IGN); X kill(child_pid, SIGTERM); X break; X X case HUPCHAR: /* Hangup */ X hangup(); X break; X X case HELPCHAR: /* Terminal Mode Help */ X termhelp(); X break; X X case '\n': /* See if NL translation in effect */ X if (nlmode) X c = '\r'; X X default: /* just send the character to the port */ X send_mbyte(c); X break; X } X } while(c != ENDCHAR); X X while(wait((int *) 0) >= 0) /* wait for the read process to die */ X ; X X if (spt_flag) { X do_script(spt_file); X goto reterm; X } X X fprintf(tfp,"\r\nLeaving Terminal Mode\r\n"); X} X Xstatic void cisbmode() X{ X cismode = 2; X signal(SIGHUP, SIG_IGN); X X longjmp(rtm); X} X X/* The next three functions are only run by the port read process (child). X * They handle the capture buffer. X * X * toggle capture status X */ Xstatic void toggle() X{ X char *malloc(); X X signal(SIGIOT, toggle); /* set signal for next toggle */ X X if(capture) { X fclose(cfp); X capture = FALSE; X fprintf(tfp, "\r\n<>\r\n"); X } else { X if ((cfp = fopen(captfile, "a")) == NULL) { X fprintf(tfp,"\r\n<\r\n"); X } else { X capture = TRUE; X fprintf(tfp,"\r\n<>\r\n"); X } X } X fflush(tfp); X} X X/* cleanup, flush and exit X */ Xstatic void cleanup() X{ X if(capture){ X fclose(cfp); X fprintf(tfp,"\r\n<>\r\n"); X } X X if (cismode == 2) X fprintf(tfp,"\r\n<>\r\n"); X X fflush(tfp); X kill(parent_pid, SIGHUP); X exit(0); X} X Xstatic void newbmask() X{ X if (bitmask == 0xff) X bitmask = 0x7f; X else X bitmask = 0xff; X X if (child_pid) X kill(child_pid, SIGQUIT); X else X fprintf(tfp,"<>\r\n", bitmask == 0xff ? 8 : 7); X} X Xstatic FILE *openfile(name) Xchar *name; X{ X FILE *fp; X char *home, fullname[NMSIZE]; X X if (fp = fopen(name, "r")) X return fp; X X if (home = (char *) getenv("HOME")) { X sprintf(fullname, "%s/%s", home, name); X return fopen(fullname, "r"); X } else X return NULL; X} X X/* X * Select a script file. If the file exists, execute it, otherwise X * exit with a non-zero return. X */ Xget_script() X{ X fprintf(tfp,"\r\nEnter script file: "); X fflush(tfp); X getsome(spt_buf); X if (spt_buf[0] == '\0') { X fprintf(tfp,"\r\n<>\r\n"); X fflush(tfp); X return 1; X } X if (access(spt_buf, 04)) { X fprintf(tfp," <<- NOT FOUND\r\n"); X fflush(tfp); X return 1; X } X fprintf(tfp, "\r\n"); X fflush(tfp); X linkflag = FALSE; X spt_file = spt_buf; X return 0; X} X X/* pselect() and divert() are used by the port write process (parent). X * They produce other sources of input for the port than the keayboard. X * X * Select phone number and dial it. (Hayes - type modem) X * Phone number is stored in a file, one number per line, with the phone X * number first, followed by some space and then any comments. X * VERSION 2.1 - If line contains BAUD=nnnn, the baud rate will be changed X * to nnn. If lines contains BITS=7 or BITS=8, the bitmask X * will be changed to the specified value. X * VERSION 2.2 - If line contains SCRIPT=nnnnn, the designated script file X * will be started. X */ Xpselect() X{ X FILE *fp; X char buffer[WBSIZE + 1]; X int c, i; X X if ((fp = openfile(phonefile)) == NULL) { X fprintf(tfp,"Phonelist file '%s' not in current or home directory\r\n", X phonefile); X return; X } X X fprintf(tfp,"d=dial x=exit SPACE=next\r\n"); X do { X if(fgets(buffer, WBSIZE, fp) == NULL){ X rewind(fp); X if(fgets(buffer, WBSIZE, fp) == NULL){ X fprintf(tfp,"Empty phonelist file!\r\n"); X return; X } X } X erasln(); X for(i = 0; i < WBSIZE && (c = buffer[i]) != '\n'; i++) X fputc(c, tfp); X fputc('\r', tfp); X fflush(tfp); X while ((c=fgetc(tfp))!=' ' && c!='d' && c!='x') X fflush(tfp); X fflush(tfp); X } while(c == ' '); X erasln(); X fflush(tfp); X fclose(fp); X if(c == 'd') { X fprintf(tfp,"dialing ...\r\n"); X dialbuf(buffer); X } else { X fprintf(tfp,"exiting ...\r\n"); X } X} X Xdialbuf(buf) Xchar *buf; X{ X char *nbr, *ptr, *ptr1, c; X X if (ptr = strstr(buf, "BAUD=")) { X ptr += 5; X if (mbaud(ptr) == -1) X fprintf(tfp,"Invalid BAUD= value\r\n"); X else X fprintf(tfp,"<>\r\n", mbaud(NULL)); X } X X if (ptr = strstr(buf, "BITS=")) { X ptr += 5; X switch (*ptr) { X case '7': X if (bitmask == 0xff) X newbmask(); X break; X case '8': X if (bitmask == 0x7f) X newbmask(); X break; X default: X fprintf(tfp,"Invalid BITS= value\r\n"); X } X } X X while (isspace(*buf) && *buf) X buf++; X X if (!(*buf)) X return; X X for (nbr = buf; !isspace(*buf) && *buf; buf++) X ; X X c = *buf; X *buf = '\0'; X dial (nbr); X X *buf = c; X if (ptr = strstr(buf, "SCRIPT=")) { X ptr += 7; X ptr1 = ptr; X while (!isspace(*ptr1) && *ptr1 != '\0') X ptr1++; X *ptr1 = '\0'; X spt_file = ptr; X spt_flag = 1; X linkflag = TRUE; X } X} X X/* Divert file into input stream, with optional delay after each newline. X */ Xdivert() X{ X FILE *fp; X char buffer[NMSIZE]; X int c, i; X X fprintf(tfp,"\r\nFile? "); X getsome(buffer); X if((fp = fopen(buffer, "r")) == NULL){ X fprintf(tfp,"\r\nCan't open %s for input\r\n", buffer); X return; X } X fprintf(tfp,"\r\nThe default delay of %d can be ", DRIBBLE); X fprintf(tfp,"changed by typing the new delay after the 'y'\r\n"); X fprintf(tfp,"Delay after every newline (y/n)? "); X X getsome(buffer); X fprintf(tfp,"\r\n"); X X i = 0; X if(mklow(buffer[0]) == 'y' && (i = atoi(buffer + 1)) == 0) X i = DRIBBLE; X while((c = getc(fp)) != EOF) X if(c != '\n') X send_mbyte(c); X else { X send_mbyte('\r'); X if(i) X sleep((unsigned) i); X } X fclose(fp); X} X Xstatic char *thtext[] = { X "Special Terminal Mode Keys:\r\n", X " ALT-c toggle capture mode\r\n", X " ALT-d dial a phone number\r\n", X " ALT-h hangup phone\r\n", X " ALT-g execute a script file\r\n", X " ALT-s send file through modem\r\n", X " ALT-x exit terminal mode\r\n", X " ALT-? help (this message)\r\n", X NULL X}; X Xtermhelp() X{ X char **txtp; X X for (txtp=thtext; *txtp != NULL; txtp++) { X fprintf(tfp,*txtp); X } X fflush(tfp); X} /