[unix-pc.sources] tstmodem

vern@zebra.UUCP (Vernon C. Hoxie) (09/10/89)

This is the final part.  Some of the problems I have encountered that
arn't mentioned in the text are:

	1. The abilitiy for another modem to login is limitd by the
numbers of 'clists' available.  As you have read about this in the past
you know that Lenny and Gil have been working on this and it should be
fixed if 3.51c is ever released.  In the meanwhile, you should reboot
every day or two to reset the number of 'clists' to max.

	2. When running with a combo board, the DTR doesn't drop after a
call is completed.  A partial work around is the shell script include
here in the lenny directory.  This replaces the '/etc/inittab' call to
'uugetty' and performs the DTR drop before starting up a new 'uugetty'. 
However, if you call out and the login fails, the old 'uugetty' doesn't
die so DTR doesn't get dropped and you are left with the modem
configured wrong for answering.

	Until these get fixed or a better work around is developed, this
program should give you a tool with which to examine your modem and
learn something about I/O interfaces.

vern-

---------------------------- cut here ----------------------------------

#! /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 archive 4 (of 4)."
# Contents:  tstmodem.3.c tstmodem.4.c
# Wrapped by vern@zebra on Mon Aug 21 22:11:29 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f tstmodem.3.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"tstmodem.3.c\"
else
echo shar: Extracting \"tstmodem.3.c\" \(18508 characters\)
sed "s/^X//" >tstmodem.3.c <<'END_OF_tstmodem.3.c'
X/* Version 1.0		Aug 21, 1989 */
X
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X *									 *
X *		Copyright (c) Aug 21, 1989 by Vernon C. Hoxie		 *
X *									 *
X *	This source code may be freely distributed as long as this	 *
X *	copyright notice is included.  No monetary charges should	 *
X *	be made in excess of the cost of copying and distribution.	 *
X *									 *
X *	Any profits which might be derived from the sale of this	 *
X *	work must be shared with me.  Other monetary contributions	 *
X *	will be gratefully accepted.					 *
X *									 *
X *		Vernon C. Hoxie						 *
X *									 *
X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X/* 'tstmodem.3.c' contains the various routines used in the MODEM */
X/* mode. */
X
X#include "tstmodem.h"
X
X#define P2LINES 4
XWINDOW *w3;				/* General screen presentation */
XWINDOW *w8;				/* Send warning messages */
XWINDOW *p3;				/* Prompt sub-window */
X
X/* array for pointers to strings to be displayed at bottom of screen.
X * These strings are loaded from the file "blazer.strgs" during the
X * "load_prompts" routine.
X *  CAUTION: the "blazer.strgs" file has inbedded NUL characters which
X *  are normally not displayed with "vi".
X *  Do not edit "blazer.strgs" unless you can display NUL.
X *  Refer to the notes in stgfilter.c. */
X
Xextern char *load_prompts();
Xextern void sho_help();
Xextern void sig_timeout();
Xextern void mpause();
Xextern void logit();
Xextern void what();
X
Xstatic char changes[ 20 ][ 20 ];/* Corrections to be sent to modem */
Xstatic int index = 0;		/* Index to next open 'changes' */
Xchar fact[ 768 ];		/* The regiter display */
Xchar *bbuf;
Xstatic char ok[] = { "OK" };
Xstatic char bad[] = { "ERROR" };
Xstatic char *bptr[ 100 ];		/* Pointers to prompt data */
Xstatic int xl = 0, xm = 0, xr = 0;	/* Higlighted area and cursor */
Xstatic int oy = 0, ox = 0;
X
X/* Flip the selected register data from regular to REVERSE VIDEO or */
X/* vice versa */
X
Xvoid flip( y, xa, xb )
Xint y, xa, xb;
X
X{
X	unsigned short fch;
X	while ( xa <= xb )
X	{
X		wmove( w3, y, xa++ );
X		fch = winch( w3 );
X		if ( fch > 0xff ) fch = fch & 0xff;
X			else fch = fch | A_BOLD;
X		waddch( w3, fch );
X	}
X}
X
X	/* Display the appropiate usage messages  */
X	/* in the lower segment of the screen.	  */
X
Xint show_prompts( pptr, lncnt )
Xchar *pptr;
Xint lncnt;
X
X{
X	static char *base;
X	char *wptr;
X	int nl;
X
X	if ( pptr != 0 ) base = pptr;
X	wptr = base;
X	while ( lncnt-- > 0 && *wptr != 0 )
X		while ( *wptr++ != '\n' && *wptr != 0 );
X	wmove( p3, 0, 0 );
X	wclrtobot( p3 );
X	for ( nl = 0; *wptr != 0 && nl < P2LINES; *wptr++ )
X	{
X		if ( *wptr == '\n' ) nl++;
X		waddch( p3, *wptr );
X	}
X	nl = *wptr;
X	return( nl );
X}		/* show_prompts() */
X
Xscroll_prompts()
X
X/* When the number of line in the prompt window exceeds the */
X/* size of the window, permit scrolling in the sub-window.  */
X
X{
X	unsigned short sch = 0;
X	int cnt = 0;
X	int flag;
X	if ( flag = show_prompts( 0, 0 ))
X	{
X		keypad( p3, TRUE );
X		while ( sch != KEY_OPTIONS && sch != KEY_EXIT
X			&& sch != KEY_LEFT && sch != KEY_RIGHT
X			&& sch != KEY_PPAGE )
X		{
X			if ( sch == KEY_UP && cnt > 0 )
X				flag = show_prompts( 0, --cnt );
X			else if ( sch == KEY_DOWN && flag > 0 )
X				flag = show_prompts( 0, ++cnt );
X			else if ( sch == KEY_HELP )
X			{
X				sho_help( 9 );
X				touchwin( w3 );
X				wnoutrefresh( w3 );
X				touchwin( p3 );
X				wnoutrefresh( p3 );
X				doupdate();
X			}
X			wattron( p3, A_REVERSE );
X			if ( cnt > 0 ) mvwprintw( p3, 0, 75, "MORE" );
X			if ( flag > 0 )
X				mvwprintw( p3, P2LINES-1, 75, "MORE " );
X			wstandend( p3 );
X			wrefresh( p3 );
X			sch = wgetch( p3 );
X		}
X	}
X	wattron( p3, A_REVERSE );
X	if ( flag > 0 ) mvwprintw( p3, P2LINES-1, 73, "<Opts>" );
X	wattroff( p3, A_REVERSE );
X	wrefresh( p3 );
X	keypad( p3, FALSE );
X}		/* scroll_prompts() */
X
X/* Select the appropiate message from the 'blazer.strgs' file for */
X/* display as prompts in a subwindow at the bottom of the screen. */
X/* The message is accociated with register currently highlighted. */
X
Xvoid domanual( pt, y )
Xint pt, y;
X/* pt indicates to search in + or - direction from last index to bbuf[] */
X/* y is the line number for the mvinch() command */
X
X{
X	char *wptr, *vptr;
X	static int num = 0;
X	int x2, x3, flag;
X	char dbuf[10];
X
X	wptr = dbuf;
X	x2 = xl;		/* xl is the coord left of entry */
X	x3 = xm - 1;		/* xm is coord of first numeral */
X	if ( x3 <= x2 ) x3 = x2 + 1;
X				/* Read from the screen to dbuf */
X	while ( x2 < x3 && wptr < dbuf + sizeof( dbuf ))
X		*wptr++ = mvwinch( w3, y, x2++ );
X	*wptr = '\0';		/* terminate with a null */
X	do
X	{		/* Look for prompt message under the cursor */
X		x2 = xl;
X		wptr = dbuf;
X		vptr = bptr[ num ];  /* Begin search from where we were */
X		while ( *wptr++ == *vptr++ && x2++ <= x3 );
X		if ( x2 >= x3 ) flag = 0;
X		else if ( pt > 0 ) flag = ++num;
X		else flag = num--;
X	} while ( flag && num < 75 && num > 0 );
X	if ( num > 75 ) num = 75;
X	else if ( num < 0 ) num = 0;
X	if ( x2 = ( show_prompts( bptr[ num ], 0 )) != 0 )
X	{
X		wattron( p3, A_REVERSE );
X		mvwprintw( p3, P2LINES-1, 73, "<Opts>" );
X		wstandend( p3 );
X	}
X	touchwin( w3 );
X}	/* domanual */
X
X/* Make the data registers appear in reverse video as the cursor */
X/* is moved about the screen. */
X
Xint highlite( y, x )
Xint y, x;
X
X{
X	int pt;
X	int xt = xl;	/* xl is coord of left side of highlight */
X	
X	unsigned short hch = mvwinch( w3, y, xt );
X
X		/* oy and ox are old coords, pt will  */
X		/* indicate change in + or - direction */
X	if ( y > oy || x > ox ) pt = 1;
X	else if ( y < oy || x < ox ) pt = -1;
X	else pt = 0;
X	if ( y != oy )
X	{
X	/* Go to new line and move left until a ' ' is encountered, */
X		while ( xt > 0 && hch == ' ' )
X			hch = mvwinch( w3, y, --xt ) & 0xff;
X	/* then move further left until first graphic character.    */
X		while ( xt > 0 && hch > ' ')
X			hch = mvwinch( w3, y, --xt ) & 0xff;
X	}
X	else if ( x > ox )
X	{
X	/* move right until first ' ' is encountered */
X		while ( hch > ' ' )
X		{
X			if ( xt >= 79 ) return( xm );
X			hch = mvwinch( w3, y, ++xt ) & 0xff;
X		}
X	}
X	else if ( x < ox )
X	{
X		/* move left to first space */
X		while ( xt > 0 && hch > ' ' )
X			hch = mvwinch( w3, y, --xt ) & 0xff;
X
X		/* then continue left past any spaces */
X		while ( xt > 0 && hch == ' ' )
X			hch = mvwinch( w3, y, --xt ) & 0xff;
X
X		/* and then further left to ' ' just */
X		/* left of the next set of literals */
X		while ( xt > 0 && hch > ' ' )
X			hch = mvwinch( w3, y, --xt ) & 0xff;
X	}
X
X	/* All three of the preceding if's have positioned xt to zero */
X	/* or to the space to the left of the desired set of literals.*/
X	/*  Now move right to the first character. */
X	while ( hch == ' ' )
X	{
X		if ( xt >= 79 ) return( xm );
X		hch = mvwinch( w3, y, ++xt ) & 0xff;
X	}
X		/* Abort if reading 'Version' or 'BA' */
X	if ( hch == 'V' && ( mvwinch( w3, y, xt + 1 ) & 0xff ) == 'e' )
X			 return( 0 );
X	else if ( hch == 'B' && ( mvwinch( w3, y, xt + 1) & 0xff ) == 'A')
X			 return( 0 );
X	
X/* Turn off highlighting of old position using old values before they */
X/* are changed.  Then set all parameters to the position of the first */
X/* character. */
X	flip( oy, xl, xr );
X	xl = xt;
X	xr = xt;
X	xm = 0;
X
X/* Move to the right hand ' ' and set the value for the cursor position */
X/* in passing. */
X	while (( xr < 79 ) && hch > ' ' )
X	{
X		hch = mvwinch( w3, y, ++xr ) & 0xff;
X		if ( !xm && ( hch == '=' || hch == ':' )) xm = xr + 1;
X	}
X	xr--;
X	if ( xm == 0 ) xm = xr;
X	if ( hch = ( mvwinch(w3, y, xl ) & 0xff ) == 'N' ) xr = xm + 15;
X	if ( pt != 0 ) domanual( pt, y );
X/* Turn on highlighting and save the values of the first graphic  */
X/* character, the cursor position and the space to right of the */
X/* entry. */
X	flip( y, xl, xr );
X	oy = y;
X	ox = xm;
X	return( xm );
X}			/* highlite() */
X
X/* Receive a pointer to a command to be sent to the modem.  Add 'AT */
X/* at the beginning and '\r\n' at the end of the string. */
X
Xint issuecommand( pc )
Xchar *pc;
X
X{
X	int j;
X	char obuf[ 200 ];
X	char *pm;
X	char *pf = fact;
X	char *pok = ok;
X	char *pbad = bad;
X	int okay = 0;
X	int error = 0;
X
X	alarm( 25 );
X	signal( SIGALRM, sig_timeout );
X	if ( setjmp( place ))
X	{
X		logit( fact );
X		do_err( "No response to a write to modem. " );
X		touchwin( w3 );
X		return( 0 );
X	}
X	mvwprintw( w3, 0, 0, "Reading:" );
X	wclrtoeol( w3 );
X	wrefresh( w3 );
X
X	strcat( strcat( strcpy( obuf, "AT" ), pc ), "\r\n" );
X	what( 1 );
X	logit( obuf );
X	j = write( tiofd, obuf, strlen( obuf ));
X	while ( !okay && !error )
X	{
X		if (( j = read( tiofd, modem, sizeof( modem ))) != 0 )
X		{
X/* transfer recieved block of data which is in 'modem' to continuous */
X/* block in 'fact'.  Check for returned 'OK' or 'ERROR'. */
X
X			modem[ j ] = '\0';
X
X		 	pm = modem;
X			while (( *pf = *pm )
X				&& ( pf < fact + sizeof( fact )))
X			{
X				if ( *pm == *pok ) *pok++;
X					else pok = ok;
X				if ( !*pok ) okay = TRUE;
X				if ( *pm == *pbad ) *pbad++;
X					else pbad = bad;
X				if ( !*pbad ) error = TRUE;
X				pf++; pm++;
X			}
X		}
X	}
X	alarm( 0 );
X	what( 3 );
X	logit( fact );
X	if ( error )
X	{
X		do_err( "ERROR read from Modem " );
X		return( 0 );
X	}
X	else if ( okay ) return( 1 );
X	return( 0 );
X}		/* issuecommand() */
X
X/* Send 'ATN?' to the modem and read in the response from the modem. */
X/* The data returned from the modem is in a generally good format */
X/* for display.  Indentations is added to center the top line and */
X/* the 'N' register format is folded so that the entire set of data */
X/* may displayed on one screen. */
X
Xint display()
X
X{
X	int j, k, m;
X	char *pf, *pfi;
X	if (( j = issuecommand( "N?" )) > 0 )
X	{
X		pf = fact;
X		k = 2;
X		j = 20;
X		m = 0;
X	 /* scuttle echoed command */
X		while ( *pf++ != 'E' );
X		pf--;
X		while ( *pf && pf < ( fact + sizeof( fact )))
X		{
X			mvwaddch( w3, k, j++, *pf );
X			if ( *pf++ == '\n' )
X			{
X				pfi = pf;
X				if ( *pfi == 'N' )
X				{
X					/* put N*'s in middle of screen */
X					if (*++pfi == '5')
X					{
X						m = 35;
X						k -= 5;
X					}
X				}
X					/* scrap 'OK' */
X				if ( *pfi == 'O' )
X				{
X					if (*++pfi == 'K')
X					break;
X				}
X				k++; j = m;
X			}
X		}
X		if ( *pf )
X		{
X			flip( oy, xl, xr );
X			mvwprintw( w3, 0, 0, "Fresh   " );
X		}
X		else mvwprintw( w3, 0, 0, "Corrupt " );
X	}
X	else mvwprintw( w3, 0, 0, "Bad read" );
X	return( 0 );
X}			/* display() */
X
X/* Read in changes to be sent to the modem.  Up to twenty changes */
X/* are cached so that a single change can be made. */
X
Xunsigned short readnum( ich, y, x )
Xunsigned short ich;
Xint y, x;
X
X{
X	int xt, xx, leave, save;
X	char nch, wch;
X	char iline[20];
X	char cache[20];
X	char *pi, *pc;
X
X	w8 = newwin( 3, 80, 0, 0 );
X	wattron( w8, A_REVERSE );
X	mvwprintw( w8, 0, 10,
X	"<Left>, <Right> to position cursor. <Exit>, <Cancl> to leave.");
X	mvwprintw( w8, 1, 10,
X	"         <Up>, <Down>, <Enter> <Save> to enter data.         ");
X	wattroff( w8, A_REVERSE );
X	wrefresh( w8 );
X	delwin( w8 );
X
X		/* Read parameter from screen using xl, xm, and xr */
X		/* established in the highlite routine, */
X	pi = iline;
X	xt = xl;
X	while ( xt <= xr ) *pi++ = mvwinch( w3, y, xt++ ) & 0xff;
X	*pi = '\0';
X		/* Then move it to cache for reference */
X		/* during backspace and abort. */
X	pi = iline;
X	pc = cache;
X	while ( *pc++ = *pi++ );
X
X	nch = iline[ 0 ];
X	if ( nch == 'S' ) xx = 3;
X	else if ( nch == 'N' ) xx = 15;
X	else xx = 1;
X/* Position pi and pc to the character under the cursor. */
X	xt = ( xm - xl );
X	pi = iline + xt;
X	pc = cache + xt;
X	wattron( w3, A_BOLD );
X	save = FALSE;
X	leave = FALSE;
X	do
X	{
X		wch = ich & 0xff;
X		if ( isgraph( wch )) switch ( nch )
X		{	/* Prohibit entry of illegal values */
X			
X			case 'P': 
X			case 'T': wch = toupper( wch );
X				  if ( wch == 'P' || wch == 'T')
X						  iline[ 0 ] = wch;
X				  iline[ 1 ] = '\0';
X				  break;
X			case 'V': if ( *cache + 1 == 'e' )
X				  {
X					leave = TRUE;
X					break;
X				  }
X			case 'E': if ( wch > '1' ) break;
X			case 'F':
X			case 'M': if ( wch > '2' ) break;
X			case 'X': if ( wch > '3' ) break;
X			case 'Q': if ( wch > '7' ) break;
X			case 'S': if ( wch > '9' ) break;
X			case 'N':
X				if (x < xm + xx)
X				{
X					*pi++ = wch;
X					*pc++;
X					x++;
X				}
X		}
X		mvwprintw( w3, y, xl, "%s", iline );
X		ich = mvwgetch( w3, y, x );
X		switch ( ich )
X		{
X			case '\b': if ( x > xm )
X				{
X					*--pi = *--pc;
X					x--;
X				}
X				break;
X			case KEY_LEFT: if ( x > xm )
X				{
X					wmove( w3, y, --x );
X					*pi--;
X					*pc--;
X				}
X				break;
X			case KEY_RIGHT: if ( x < ( xm + xx ))
X				{
X					wmove( w3, y, ++x );
X					*pi++;
X					*pc++;
X				}
X				break;
X			case KEY_HELP:	sho_help( 10 );
X					touchwin( w3 );
X					break;
X			case '\n':
X			case KEY_SAVE:
X			case KEY_UP:
X			case KEY_DOWN: save = TRUE;
X			case KEY_EXIT:
X			case KEY_CANCEL: leave = TRUE;
X		}
X	} while ( !leave );
X
X		/* the 'enter' and 'return' keys both return a value */
X		/*  of 10 and neither are translated to KEY values   */
X		/* by curses.  KEY_BACKSPACE is also useless.	     */
X
X	if ( save )
X	{
X		xt = 0;
X		xx = 0;
X		wmove( w3, 0, 0 );
X		wclrtoeol( w3 );
X		while (( nch = changes[ xt ][ 0 ]) != '\0' && xt < 20
X			&& xx == 0)
X		{	/* If this register has been changed,    */
X			/*  change the change. :-) 		 */
X			if ( changes[ xt ][ 0 ] == iline[ 0 ])
X				switch ( nch )
X			{
X				case 'N': if ( changes[ xt ][ 1 ]
X						 != iline[ 1 ]) break;
X				case 'E':
X				case 'F':
X				case 'M':
X				case 'Q':
X				case 'P':
X				case 'T':
X				case 'V':
X				case 'X': xx = xt; break; 
X				case 'S': x = 1;
X					  while (
X						changes[ xt ][ x ]
X							== iline[ x ]
X					        && x++ < 5);
X					  if ( x == 4 ) xx = xt; break;
X			}
X			xt++;
X		}
X		if ( xx == 0 ) xx = index++;
X		if ( index >= 20 )
X		{
X			mvwprintw( w3, 0, 26, "Change Buffer Full" );
X			wclrtoeol( w3 );
X			return( 0 );
X		}
X		else mvwprintw( w3, 0, 26,
X			"Change Buffer has %d entries. ", index );
X		if ( xx > 20 ) return( 21 );
X		pc = changes[ xx ];
X		pi = iline;
X		while ( *pc++ = *pi++ );
X		while ( pc < changes[ xx ]) *pc++ = '\0';
X	}
X	else mvwprintw( w3, y, xl, "%s", cache );
X	wattroff( w3, A_BOLD );
X	touchwin( w3 );
X	if ( ich == KEY_UP || ich == KEY_DOWN ) return( ich );
X	else return( 0 );
X}
X
X/* Entered by the SEND key.  This concatenates the up to twenty changes */
X/* cached by 'readnum' and sends them to 'issuecommand()' for actual */
X/* transmission. */
X
Xvoid send_changes()
X
X{
X	int x, y, xt;
X	char *optr, *sptr;
X	char buf[205];
X	unsigned short sch = 0;
X	w8 = newwin( 5, 80, 18, 0 );
X	keypad( w8, TRUE );
X		/* Show the changes to be made */
X	for ( y = 1, x = 0, xt = 0; xt < 20; xt++ )
X	{
X		mvwaddstr( w8, y++, x, changes[ xt ] );
X		if ( y == 5 )
X		{
X			y = 1;
X			x += 15;
X		}
X	}
X	wattron( w8, A_BOLD );
X	mvwprintw( w8, 0, 14,
X		"The following changes will be made, <Cancl> <Enter> ");
X	wattroff( w8, A_BOLD );
X	wrefresh( w8 );
X	do
X	{
X		sch = wgetch( w8 );
X		if ( sch == KEY_HELP )
X		{
X			sho_help( 11 );
X			touchwin( w3 );
X			wnoutrefresh( w3 );
X			touchwin( w8 );
X			wnoutrefresh( w8 );
X			doupdate();
X		}
X	} while ( sch != KEY_CANCEL && sch != KEY_F(2) && sch != 10 );
X	
X	if ( sch == 10 )
X	{
X		sptr = buf;
X		for ( xt = 0; xt < 20; xt++ )
X		{
X			/* The N lines have a ':' instead of '=' */
X			for ( optr = changes[ xt ]; *sptr = *optr; sptr++)
X			{
X				if ( *sptr == ':' ) *sptr = '=';
X				while ( *++optr == ' ' );
X			}
X		}
X		if ( issuecommand( buf )) display();
X		else mvwprintw( w3, 0, 0, "Error>> " );
X		xt = sizeof( changes );
X			/* Clear out old data and reset the index */
X		for ( optr = changes[0]; xt > 0; xt-- ) *optr++ = '\0';
X		index = 0;
X	}
X	keypad( w8, FALSE );
X	delwin( w8 );
X	touchwin( w3 );
X}
X
X/* Give the user an option to cancel a write to the EEPROM before */
X/* the command is actually sent. */
X
Xquery()
X
X{
X	char qch;
X	w8 = newwin( 5, 80, 18, 0 );
X	keypad( w8, TRUE );
X	wattron( w8, A_REVERSE );
X	nocbreak();
X	mvwprintw( w8, 0, 0,
X"Caution! EEPROM's have limited number of write's per lifetime!" );
X	wclrtoeol( w8 );
X	mvwprintw( w8, 1, 0,
X"             <Cancl> to abort, <Enter> to write.              ");
X	wclrtoeol( w8 );
X	wattroff( w8, A_REVERSE );
X	do
X	{
X		qch = wgetch( w8 );
X		if ( qch == KEY_HELP )
X		{
X			sho_help( 12 );
X			touchwin( w3 );
X			wnoutrefresh( w3 );
X			touchwin( w8 );
X			wnoutrefresh( w8 );
X			doupdate();
X		}
X		else if ( qch == 10 || qch == KEY_F(3) )
X		{
X			issuecommand( "&W" );
X			display();
X			break;
X		}
X		else if ( qch == KEY_EXIT || qch == KEY_CANCEL ) break;
X	} while ( qch == 0xffff );
X	halfdelay( 1 );
X	keypad( w8, FALSE );
X	delwin( w8 );
X	touchwin( w3 );
X}
X
X/* The main control screen for the MODEM mode. */
X
Xvoid showstuff()
X
X{
X	void restore();
X	
X	unsigned short sch;
X	int y;
X	int x;
X	char ch;
X	if ( oy == 0 )
X	{
X		oy = 2;
X		ox = 0;
X	}
X	y = oy;
X	xm = ox;
X	if ( ! issuecommand( '\0' )) do_err( "Can't start modem." );
X 	display();
X	highlite( y, xm );
X	x = xm;
X	noecho();
X	labels( w3, 2 );
X	sch = KEY_DOWN;
X	do
X	{
X		if ( sch < 0x7f )
X		{
X			ch = toupper( sch );
X			if ( isdigit( ch ) || ch == 'P' || ch == 'T' )
X					sch = readnum( ch, y, x );
X		}
X		switch ( sch )
X		{
X			/* read modem */
X			case KEY_F(1): display(); break;
X			case KEY_F(2): send_changes(); break;
X			/* write to eeprom */
X			case KEY_F(3): query(); break;
X			/* read eeprom */
X			case KEY_F(4): issuecommand( "&E" );
X				       display();
X				       break;
X			/* read factory */
X			case KEY_F(5): issuecommand( "&F" );
X				       display();
X				       break;
X			case KEY_F(6): break;
X			case KEY_F(7): edit_tio();
X				       touchwin( w3 );
X				       break;
X			case KEY_F(8): break;
X			case KEY_NPAGE:
X			case KEY_OPTIONS: scroll_prompts(); break;
X			case KEY_HELP:
X			case KEY_COMMAND: sho_help( 8 );
X					  touchwin( w3 );
X					  break;
X			case KEY_LEFT: if ( x > 0 ) x--;
X					x = highlite( y, x );
X					break;
X			case KEY_UP: if ( y > 2 ) y -= 1;
X					else y = 2;
X					if (( x = highlite( y, x )) == 0)
X					{
X						x = xm;
X						y += 1;
X					}
X					break;
X			case KEY_RIGHT: if ( x < 79 ) x++;
X					if (( x = highlite( y, x )) == 0 )
X						x = xm;
X					break;
X			case KEY_DOWN: if ( y < 16 ) y++;
X					else y = 16;
X					x = highlite( y, x );
X					break;
X		}
X		wrefresh( w3 );
X		flushinp();
X		sch = mvwgetch( w3, y, x );
X	} while ( sch != KEY_EXIT && sch != KEY_F(8) );
X	return;
X}
X
X/* Entry routine for setting up the MODEM mode */
X
Xvoid do_registers()
X
X{
X	void restore();
X	
X	w3 = newwin( 0, 0, 0, 0 );
X	p3 = subwin( w3, P2LINES, 80, 18, 0 );	/* set subwindow */
X	wclear( w3 );
X	keypad( w3, TRUE );
X	bbuf = load_prompts( modprmpt, bptr, 100 );
X	showstuff();
X	restore();
X}
X
X/* Exit routine for closing up the various window and files used by */
X/* the MODEM mode. */
X
Xvoid restore()
X{
X	if ( bbuf ) free( bbuf );
X	keypad( w3, FALSE );
X	echo();
X	wclear( w3 );
X	wrefresh( w3 );
X	delwin( p3 );
X	delwin( w3 );
X	return;
X}
END_OF_tstmodem.3.c
if test 18508 -ne `wc -c <tstmodem.3.c`; then
    echo shar: \"tstmodem.3.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f tstmodem.4.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"tstmodem.4.c\"
else
echo shar: Extracting \"tstmodem.4.c\" \(19606 characters\)
sed "s/^X//" >tstmodem.4.c <<'END_OF_tstmodem.4.c'
X/* Version 1.0		Aug 21, 1989 */
X
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
X *									 *
X *		Copyright (c) Aug 21, 1989 by Vernon C. Hoxie		 *
X *									 *
X *	This source code may be freely distributed as long as this	 *
X *	copyright notice is included.  No monetary charges should	 *
X *	be made in excess of the cost of copying and distribution.	 *
X *									 *
X *	Any profits which might be derived from the sale of this	 *
X *	work must be shared with me.  Other monetary contributions	 *
X *	will be gratefully accepted.					 *
X *									 *
X *		Vernon C. Hoxie						 *
X *									 *
X * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X/* 'tstmodem.3.c' contains the routines to support the COMMAND mode. */
X
X
X#include "tstmodem.h"
X
XWINDOW *w4;
XWINDOW *sw4;
XFILE *log_fd;
X
Xextern void sho_help();
Xextern void sig_timeout();
Xextern void mpause();
Xextern void logit();
Xextern void what();
X
Xvoid clearbuf();
Xchar wrds[ 165 ];
Xstatic char ok[] = { "OK" };
X
Xstatic new_nls = 0;
Xint Nonl;
Xint show_raw, chat;
X
Xvoid reset()
X
X{
X	nocbreak();
X	halfdelay(1);
X	show_it( LOGSZ + 2 );
X}
X
X/* Display a page of information from the log file onto the center */
X/* of the screen.  Scrolling is accomplished by the value passed */
X/* to 'show_it'.  These values are +1, -1, +LOGSZ+2 or -(LOGSZ+2) */
X
Xint show_it( num )
Xint num;
X
X{
X	char wrds[ 85 ];
X	char *pa, *pb;
X	static long old_beg;
X	static long last_page;
X	int i;
X	if ( num == 0 ) return( 0 );
X
X/* 'last_page' is a pointer to the LOGSZ'th line from eof, */
X/*  it is set in 'logit()' below. */
X
X	if ( num > LOGSZ )			/* SHIFT HOME */
X	{
X		fseek( log_fd, last_page, 0 );
X		while ( new_nls > LOGSZ )
X		{
X			fgets( wrds, 80, log_fd );
X			last_page = ftell( log_fd );
X			new_nls--;
X		}
X		old_beg = last_page;
X	}
X	else if ( num < - ( LOGSZ )) old_beg = 0;	/* HOME */
X	else if ( num < 0 )
X	{
X		while( num <= 0 )	/* UP or SHIFT PAGE */
X		{
X			num++;
X			do
X			{
X				if (old_beg <= 0) goto PRINT;
X				fseek( log_fd, --old_beg, 0 );
X			} while ( fgetc( log_fd ) != '\n' );
X		}
X		old_beg++;
X	}
X	else while ( num > 0 )	/* DOWN or PAGE */
X	{
X		do
X		{
X			if ( old_beg >= last_page ) break;
X			fseek( log_fd, old_beg++, 0 );
X		} while ( fgetc( log_fd ) != '\n' );
X		num--;
X	}
X	
XPRINT:	fseek( log_fd, old_beg, 0 );
X	wmove( sw4, 0, 0 );
X	wclrtobot( sw4 );
X	for ( i = LOGSZ; i ; i-- )
X	{
X		if (( pb = fgets( wrds, 84, log_fd )) == 0 ) break;
X		for ( pa = wrds; *pa; pa++ )
X			if ( *pa != '\r' ) waddch( sw4, *pa );
X	}
X	if ( old_beg == last_page && new_nls == LOGSZ
X		&& pb != 0 )
X	{
X		new_nls++;
X		show_it( LOGSZ + 2 );
X	}
X	touchwin( w4 );
X	wrefresh( w4 );
X	return( 0 );
X}					/* show_it() */
X
X/* Convert data slated for logging into lines of less than eighty */
X/* characters.  Also, the conversion from standard display format */
X/* into the 'raw' format is accomplished here.  This data conversion */
X/* is a feature of the COMMAND mode only.  Data logged in MODEM or */
X/* TERMIO will not be converted to 'raw'. */
X
Xvoid stow_it( strg )
Xchar *strg;
X
X/* 'wrds' is a null terminated string to which the contents of 'strg' */
X/* are concatenated after processing */
X
X{
X	int k;
X	static int col = 0;
X	static char cache[85];
X	char *cpt;
X	short och;
X	cpt = cache;
X	if ( *strg != '\0' ) do
X	{
X		och = *strg;
X		if ( show_raw )
X		{
X			k = 0;
X			if ( och > 127 || och < 0 )
X			{	/* convert meta characters */
X				och = och & 0x7f;
X				*cpt++ = 'M';
X				*cpt++ = '-';
X				col += 2;
X			}
X			else if ( och <= ' ' )
X			{	/* convert control characters */
X				switch (och)
X				{
X					case 8:   k = 'b'; break;
X					case 9:   k = 't'; break;
X					case 10:  k = 'n'; break;
X					case 13:  k = 'r'; break;
X					case ' ': k = 's'; break;
X				}
X			}
X			if ( k )
X			{
X				*cpt++ = '\\';
X				och = k;
X				col += 1;
X			}
X			else if ( och < ' ' )
X			{
X				*cpt++ = '^';
X				och = och + 64;
X				col += 1;
X			}
X			else if ( och == 127 )
X			{
X				*cpt++ = '^';
X				och = '?';
X				col += 1;
X			}
X			if ( col > 75 ) col += 5;
X		}
X		if (( och >= ' ' && och < 127 )
X			|| ( !Nonl && och == '\n' )
X			|| (  Nonl && och == '\r' )
X			|| och == '\t' )
X		{
X			if ( och == '\t' ) col += 8;
X			else if ( Nonl && och == 'r' ) och = '\n';
X			else col += 1;
X			*cpt++ =  och;
X		}
X		if ( *strg == '\0' || col >= 78 )
X		{
X			if (( col >= 78 || show_raw )
X				&& ( *( cpt - 1 ) != '\n' ))
X						*cpt++ = '\n';
X			*cpt = '\0';
X			och = *( strg - 1 );
X			if (( !Nonl && och == 'n' )
X					|| ( Nonl && och == 'r'
X					|| col >= 78 )) col = 0;
X			logit( cache ); 
X			cpt = cache;
X		}
X	} while ( *strg++ && cpt < cache + sizeof(cache) );
X	show_it( LOGSZ + 2 );
X}				/* end of stow_it() */
X
X/* Take a strings of data from the 'data lines' and convert any special */
X/* escaped charaters to the appropiate control character before sending */
X/* to the modem. */
X
Xvoid send_mod(bpt)
Xchar *bpt;
X
X{
X	static char eot[] = {"EOT"};
X	static char brk[] = {"BREAK"};
X	char ch, out[64], *opt, *ept, *brpt, *test;
X	int dump, nonl;
X	if ( *bpt == '\0' ) return;
X	nonl = FALSE;
X	what( 1 );
X	stow_it( bpt );
X	opt = out;
X	do
X	{
X		test = bpt;
X		ept = eot;
X		while (*test++ == *ept++);
X		if (! *ept)
X		{
X			*opt++ = '\04';
X		    	write( tiofd, out, opt - out );
X			bpt = test;
X			opt = out;
X		}
X		test = bpt;
X		brpt = brk;
X		while (*test++ == *brpt++);
X		if (! *brpt)
X		{
X		    	write( tiofd, out, opt - out );
X			ioctl(tiofd, TCSBRK, 0);
X			bpt = test;
X			opt = out;
X		}
X		dump = FALSE;
X		while ( *bpt == '\\' )
X		{
X			switch ( *++bpt )
X			{
X				case '0': ch = '\0';
X					  while ( isdigit( *bpt ))
X				  ch = ( ch << 3 ) | ( *bpt++ & 0x07 );
X					  *opt = ch;
X					  bpt--;
X					  break;
X				case 'b': *opt = 8;
X					  break;
X				case 'c': dump = !dump;
X					  nonl = TRUE;
X					  break;
X				case 'C': Nonl = !Nonl;
X					  return;
X					  break;
X				case 'd': if ( dump = !dump ) break;
X					  sleep(DELAY);
X					  nonl = TRUE;
X					  break;
X				case 'K': if ( dump = !dump ) break;
X					  ioctl( tiofd, TCSBRK, 0 );
X					  nonl = TRUE;
X					  break;
X				case 'n': *opt = '\n';
X					  break;
X				case 'N': *opt = '\0';
X					  break;
X				case 'p': if ( dump = !dump ) break;
X					  mpause( PAUSE );
X					  nonl = TRUE;
X					  break;
X				case 'r': *opt = '\r';
X					  break;
X				case 's': *opt = ' ';
X					  break;
X				case 't': *opt = '\t';
X					  break;
X				case '\\': *opt = '\\';
X					  break;
X				default: *opt = '\\';
X					 *++opt = *bpt;
X					 break;
X			}			
X			if ( dump )
X			{
X				*opt = '\0';
X			    	write( tiofd, out, opt - out );
X				opt = out;
X				--opt;
X				--bpt;
X			}
X			else
X			{
X				opt++;
X				bpt++;
X			}
X		}
X		if ( *bpt == '\n' )
X		{
X			if ( Nonl ) *bpt = '\r';
X			if ( nonl )
X			{
X				bpt++;
X				nonl = FALSE;
X			}
X		}
X	} while (( *opt++ = *bpt++ ) && ( opt < out + sizeof( out ) - 2 ));
X	if ( opt == out + sizeof( out ) - 2 ) *opt = '\0';
X	if ( opt > out ) write( tiofd, out, opt - out );
X}					/* send_mod() */
X
X/* This function first checks that the length of 'strg' is valid. */
X/* It then logs the "Expect:' entry and checks for '""'           */
X/* (expect nothing) and returns sucess.  If not '""', the modem is*/
X/* read and the returned compared with 'expect'.  If the wanted   */
X/* pattern is recognized, we return(0).  If no such pattern is    */
X/* received within 5 sec. an error is logged. */
X
Xint do_expect(expect)
Xchar *expect;
X
X{
X	char temp[40];
X	char ch;
X	unsigned short ich;
X	int j;
X	char *exp, *mpt, *tmp;
X	exp = expect;
X	tmp = temp;
X	do
X	{
X 		while (*exp == '\\')
X		{
X			switch (*++exp)
X			{
X				case '0': ch = '\0';
X					  while (isdigit(*exp))
X				  ch = (ch << 3) | (*exp++ & 0x07);
X					  *tmp = ch;
X					  exp--;
X					  break;
X				case 's': *tmp = ' ';
X					  break;
X				case 't': *tmp = '\t';
X					  break;
X				case 'n': *tmp = '\n';
X					  break;
X				case 'r': *tmp = '\r';
X					  break;
X			}
X 			exp++;
X			tmp++;
X		}
X	} while ((*tmp++ = *exp++) && (tmp < temp + sizeof(temp)-2 ));
X	if ( *tmp != '\n' ) *tmp++ = '\n';
X	*tmp = '\0';
X	what( 2 );
X	stow_it( temp );		/* log the 'Expect:' pattern */
X	exp = expect;
X	while (*exp == '"') exp++;	/* Check for "" */
X	if (! *exp)
X	{
X		what( 4 );
X		stow_it( expect );	/* log "Got it:" */
X		return( 0 );
X	}
X	alarm(20);
X	signal(SIGALRM, sig_timeout);
X	if (setjmp(place))
X		return(-1);
X	for (;;)
X	{
X		if ( wgetch( w4 ) == KEY_CANCEL )
X		{
X			alarm( 0 );
X			stow_it( "'Expect' Cancelled:\n" );
X			return( -1 );
X		}
X		if (( j = read( tiofd, modem, sizeof( modem ) -1 )) > 0 )
X		{
X			mpt = modem;
X			exp = temp;
X			modem[ j ] = '\0';
X			while ( *mpt )
X			{	/* scan for the expect pattern */
X				if ( *exp == *mpt ) exp++;
X				else exp = temp;
X				if (! *exp)
X				{	/* log "Got it:" */
X					alarm(0);
X					what( 4 );
X					stow_it( expect );
X				}
X				if ( ! *mpt || ! *exp )
X				{
X					what( 3 );
X					stow_it( modem );
X					if ( ! *exp ) return ( 0 );
X				}
X				else mpt++;
X			}
X		}
X	}
X}					/* do_expect() */
X
X/* Provide a quick means of entering certain control characters and */
X/* performing the special 'ioctl' commands. */
X
Xchar cntlchars()
X
X{
X	chtype cch;
X	int ctlch;
X	labels(w4,4);
X	mvwprintw(w4,0,0,"Select control to send to modem: ");
X	wrefresh(w4);
X	while ((cch = wgetch(w4)) == 0xffff);
X	switch (cch)
X	{
X		case KEY_F(1): ctlch = 17; break;
X		case KEY_F(2): ctlch = 19; break;
X		case KEY_F(3): ctlch = 6; break;
X		case KEY_F(4): ctlch = 21; break;
X		case KEY_F(5): mvwprintw(w4,0,0,"Enter character: ^");
X				wclrtoeol(w4);
X				wrefresh(w4);
X				while ((cch = wgetch(w4)) == 0xffff);
X				ctlch = (cch & 0x001f);
X				break;
X		case KEY_F(6): ioctl(tiofd, TCSBRK, 0);
X				ctlch = -1;
X				stow_it( "<<BRK>>" );
X				break;
X		case KEY_F(7): newgetty.c_cflag &= ~CBAUD;
X				ioctl( tiofd, TCSETA, &newgetty );
X				sleep(5);
X				newgetty.c_cflag |= B9600;
X				ioctl( tiofd, TCSETA, &newgetty );
X				ioctl( tiofd, TCFLSH, 2 );
X				ctlch = -1;
X				stow_it( "Modem reset to 9600 baud\n");
X				break;
X		case KEY_F(8): send_mod( "\\d\\c+++\c\d\c" );
X				ctlch = -1;
X				break;
X		case KEY_HELP:  sho_help( 5 );
X				touchwin( w4 );
X		default: ctlch = -1; break;
X	}
X	wmove(w4,0,0);
X	wclrtoeol(w4);
X	return(ctlch);
X}					/* cntlrchars() */
X
X/* Scan data from the modem for the 'OK\r\n' response.  Used by the */
X/* STATS and SYNC routines. */
X
Xint get_ok()
X
X{
X	int j;
X	char *pm, *pok;
X	pm = modem;
X	pok = ok;
X	j = read( tiofd, modem, sizeof( modem ));
X	if ( j )
X	{
X		modem[ j ] = '\0';
X		what( 3 );
X		stow_it( modem );
X		while( *pm )
X		{
X			if ( *pm == *pok ) pok++;
X			else pok = ok;
X			if ( ! *pok ) return( 1 );
X			pm++;
X		}
X	}
X	return( 0 );
X}
X
X/* Cycle the 'termio( 7 )' data structure with different baud rates */
X/* until an 'OK' is returned.  Modem must be in a fixed speed for */
X/* this to work. */
X
Xint sync()
X
X{
X	struct termio this_io;
X	static char *spd[] = {"0", "50", "75", "110", "134", "150",
X			"200", "300", "600", "1200", "1800", "2400",
X			"4800", "9600", "19200", "EXTB"};
X	int i;
X	int stat;
X	char speed[10];
X	unsigned short ich;
X	mvwprintw(w4, 2, 0, "Sync in progress: " );
X	stow_it("Sync: ");
X		/* Removal ICANON if that flag is set */
X	if (( ioctl( tiofd, TCGETA, &this_io )) == -1 )
X	{
X		do_err("TCGETA");
X		stat = -1;
X	}
X	this_io.c_lflag &= ~ICANON;
X	if ( ioctl( tiofd, TCSETAF, &this_io ) == -1 )
X	{
X		do_err( "System error, " );
X		stat = -1 ;
X	}
X	stat = 0;
X	alarm( 20 );
X	signal( SIGALRM, sig_timeout ); 	
X	if ( !setjmp( place )) while ( !stat )
X	{
X		if ( wgetch( w4 ) == KEY_CANCEL )
X		{
X			stow_it( "Cancelled, " );
X			stat = -2 ;
X		}
X		i = this_io.c_cflag & 017;
X		if ( ++i >= 017 ) i = 6;
X		this_io.c_cflag = ( this_io.c_cflag & 037760 ) | i;
X		if ( ioctl( tiofd, TCSETAF, &this_io ) == -1 )
X		{
X			stow_it( "System error, " );
X			stat = -1 ;
X		}
X		mpause( 10 );
X		send_mod( "at\\r\\n" );
X		mpause( 500 );
X		if ( get_ok() ) stat = 1;
X	}
X	else stat = -1;
X	alarm( 0 );
X	newgetty.c_cflag = this_io.c_cflag;
X	if ( ioctl( tiofd, TCSETAF, &newgetty ) == -1 )
X	{
X		stow_it( "System error, " );
X		stat = -1 ;
X	}
X	if ( stat > 0 ) stow_it( "Success, " );
X	else stow_it( "Failed, ");
X	strcat( strcpy( speed, spd[ i ]), "\n");
X	what( 7 );
X	stow_it( speed );
X	return( stat );
X}					/* sync() */
X
X/* Read the input from the modem during general use.  Separate reads */
X/* for the send/expect modes and other times when special responses */
X/* are expected. */
X
Xint read_mod()
X
X{
X	int j;
X	char *pm;
X	while (( j = read( tiofd, modem, sizeof( modem )-1 )) > 0 )
X	{
X		modem[ j ] = '\0';
X		what( 3 );
X		stow_it( modem );
X	}
X	return(0);
X}					/* read_mod() */
X
X/* Perform the switching when processing 'chat' scripts. */
X
Xvoid do_chat(px, size)
Xchar *px;
Xint size;
X
X{
X	char *po, *eob;
X	char obuf[30];
X	int pect, j;
X	pect = chat;
X	eob = px + size;
X	*eob = '\0';
X	while (*px)
X	{
X		po = obuf;
X					/* dump excess white space */
X		while ((*px == ' ') || (*px == '\t')) px++;
X		while (*po++ = *px++)
X		{
X			if (*px == ' ') break;
X			if (*px == '\n') break;
X			if (*px == '\t') break;
X			if (px > eob) return;
X			if (po >= (obuf + sizeof(obuf))) return;
X		}
X		*po = '\0';
X		if ( pect ) j = do_expect( obuf );
X		else send_mod( obuf );
X		if ( j == -1 ) break;
X		if ( chat ) pect = !pect;
X		else pect = 0;
X	}
X}					/* do_chat() */
X
X/* Provide for quick reading of the special statistic registers of */
X/* the Trailblazer modem.  It was intended that this could be used */
X/* with the modem 'on line', however, I have had trouble getting */
X/* the escape sequence to work. */
X
Xint stats()
X
X{
X	int cmd;
X	unsigned short ich;
X	char str1[10], str2[15], nam[20];
X	alarm( 5 );
X	signal(SIGALRM, sig_timeout);
X	if ( setjmp( place ))
X	{
X		stow_it( "Escape Sequence failure:\n" );
X		return(-1);
X	}
X	cmd = FALSE;
X	while( 1 )
X	{
X		send_mod("AT\r\n");
X		mpause(6);
X		if ( ! get_ok )
X		{
X			stow_it( "Sending Escape Sequence.\n" );
X			send_mod("\\d\\c+++\\c\\d");
X			cmd = TRUE;
X		}
X		else break;
X	}
X	alarm( 0 );
X	mvwprintw(w4, 1, 0, "<Exit> to return:");
X	mvwprintw(w4, 2, 0, "Press Function Key");
X	labels(w4,5);
X	do
X	{
X		nam[0] = '\0';
X		if ((ich = wgetch(w4)) == 0xffff) read_mod();
X		switch(ich)
X		{
X			case KEY_F(1):	strcpy(str1, "S70");
X					strcpy(nam, "Tx Rate");
X					break;
X			case KEY_F(2):	strcpy(str1, "S71");
X					strcpy(nam, "Tx Bits");
X					break;
X			case KEY_F(3):	strcpy(str1, "S72");
X					strcpy(nam, "Rx Rate");
X					break;
X			case KEY_F(4):	strcpy(str1, "S73");
X					strcpy(nam, "Rx Bits");
X					break;
X			case KEY_F(5):	strcpy(str1, "S74?\\pS75");
X					strcpy(nam, "Packets");
X					break;
X			case KEY_F(6):	strcpy(str1, "S76");
X					strcpy(nam, "Noise");
X					break;
X			case KEY_F(7):	strcpy(str1, "S77");
X					strcpy(nam, "Freq Offset");
X					break;
X			case KEY_F(8):	strcpy(str1, "S78");
X					strcpy(nam, "Line Qual");
X					break;
X			case KEY_HELP:  sho_help( 6);
X					touchwin( w4 );
X					break;
X			case KEY_EXIT:	break;
X			default: if (ich != 0xffff) beep(); break;
X		}
X		if ( nam[ 0 ] )
X		{
X			strcat( strcat( strcpy( str2, "AT" ),
X						str1 ), "?\r\n" );
X			send_mod( str2 );
X			stow_it( strcat( nam, "\n" ));
X			do_expect( "OK" );
X		}
X	} while ( ich != KEY_EXIT );
X	if ( cmd ) send_mod( "ATO\r\n");
X	wmove(w4, 1, 0);
X	wclrtoeol(w4);
X	return(0);
X}					/* stats() */
X
X/* The main controller for the screen and mode selector.  The is a busy */
X/* routine and could probably be better understood if it were broken */
X/* functional segaments.  It wasn't designed, it was grown. */
X
Xvoid do_cmd()
X
X{
X	char abuf[80], bbuf[80], cbuf[160];
X	int i, j, xx;
X	int wye, mark;
X	chtype ich;
X	char ch;
X	mark = 0;
X	xx = 0;
X	reset();
X	for (j = 0; j < sizeof(abuf); abuf[j++] = '\0');
X	for (j = 0; j < sizeof(bbuf); bbuf[j++] = '\0');
X	wye = 3;
X	typeahead( -1 );
X	setjmp( place2 );
X	do
X	{
X		labels(w4,3);
X		if (show_raw) mvwprintw( w4, 0, 0, "Raw mode   ");
X			else  mvwprintw( w4, 0, 0, "Normal mode");
X		if ( Nonl )   mvwprintw( w4, 1, 0, "\\n -> \\r " );
X			else  mvwprintw( w4, 1, 0, "         " );
X		if (chat)     mvwprintw( w4, 2, 0, "Chat script:      ");
X			else  mvwprintw( w4, 2, 0, "Enter data:       ");
X		mvwprintw( w4, 3, 0, "%s", abuf );
X		wclrtoeol( w4 );
X		mvwprintw( w4, 4, 0, "%s", bbuf );
X		wclrtoeol( w4 );
X		wmove( w4, wye, mark );
X		if (( ich = wgetch( w4 )) == 0xffff ) xx = read_mod();
X	else
X	{
X		ch = ich & 0x00ff;
X		if ( ch == 8 ) ich = KEY_BACKSPACE;
X		if ( ich > 0x7f ) switch ( ich )
X		{
X			case KEY_F(1): show_raw = !show_raw; break;
X			case KEY_F(2): chat = !chat;
X					if (! chat)
X					{
X			for (j = 0; j < sizeof(abuf); abuf[j++] = '\0');
X			for (j = 0; j < sizeof(bbuf); bbuf[j++] = '\0');
X					}
X					else strcpy( abuf, "\"\" " );
X					break;
X			case KEY_F(3): sync(); break;
X			case KEY_F(4): stats(); break;
X			case KEY_F(5): if (( ch = cntlchars()) >= 0 )
X					{
X						abuf[ mark++ ] = ch;
X						mark++;
X					}
X					break;
X			case KEY_EXIT:
X			case KEY_F(6):	break;
X			case KEY_F(7):	edit_tio();
X					reset();
X					break;
X			case KEY_F(8):	do_registers();
X					break;
X			case KEY_COMMAND:
X			case KEY_HELP:	sho_help( 4 );
X					touchwin( w4 );
X					break;
X			case KEY_BACKSPACE:
X			case KEY_SDC:	if (mark == 0) break;
X					mark--;
X			/* KEY_DC must follow KEY_SDC */
X			case KEY_DC:	if (wye == 3)
X					for (i = mark; i < 78; i++)
X						abuf[i] = abuf[i+1];
X					else for (i = mark; i < 78; i++)
X						bbuf[i] = bbuf[i+1];
X					break;
X			case KEY_DL: 	if (wye == 3)
X			  for (j = 0; j < sizeof(abuf); abuf[j++] = '\0');
X					else
X			  for (j = 0; j < sizeof(bbuf); bbuf[j++] = '\0');
X			 		break;
X			case KEY_LEFT: 	--mark;	break;
X			case KEY_RIGHT: ++mark;	break;
X			case KEY_NEXT:	while
X				((ch = mvwinch(w4,wye,++mark)) != ' ')
X				{
X					if (mark >= 79) if (wye == 3)
X					{
X						wye = 4;
X						mark = 0;
X					}
X					else
X					{
X						mark = 79;
X						break;
X					}
X				}
X				break;
X			case KEY_PREVIOUS: while
X				((ch = mvwinch(w4,wye,--mark)) != ' ')
X				{
X					if (mark <= 0) if (wye == 4)
X					{
X						wye = 3;
X						mark = 80;
X					}
X					else
X					{
X						mark = 0;
X						break;
X					}
X				}
X				break;
X			case KEY_UP: 	if (wye == 4) wye = 3;
X					else xx = -1;
X					break;
X			case KEY_DOWN: 	if (wye == 3) wye = 4;
X					else xx = 1;
X					break;
X			case KEY_HOME: xx = -(LOGSZ + 2); break;
X			case KEY_SHOME: xx = (LOGSZ + 2); break;
X			case KEY_NPAGE: xx = (LOGSZ - 1); break;
X			case KEY_PPAGE: xx = -(LOGSZ - 1); break;
X			default: if (ich != 0xffff) beep(); break;
X		}
X		else if (ch == '\n')
X		{
X			strcat(strcat(strcpy(cbuf, abuf), bbuf), "\n");
X			i = strlen(cbuf);
X			if (chat) do_chat(cbuf, i);
X			else
X			{
X				cbuf[i] = '\0';
X				send_mod(cbuf);
X				for (j = 0; j < sizeof(abuf);
X					abuf[j++] = '\0');
X				for (j = 0; j < sizeof(bbuf);
X					bbuf[j++] = '\0');
X			}
X		}
X		else if (isprint(ch)) /* Insert char typed in */
X		if (wye == 3)
X		{
X			for (i = 79; i > mark; i--) abuf[i] = abuf[i-1];
X			abuf[mark++] = ich;
X		}
X		else
X		{
X			for (i = 79; i > mark; i--) bbuf[i] = bbuf[i-1];
X			bbuf[mark++] = ich;
X		}
X	}
X	 	if (wye == 3)
X		{
X 			j = strlen(abuf);
X			if (mark > 79)
X			{
X				wye = 4;
X				mark = 0;
X			}
X 			else if (mark > j) mark = j;
X			if (mark < 0) mark = 0;
X		}
X		else
X		{
X 			j = strlen(bbuf);
X			if (mark < 0)
X			{
X				wye = 3;
X				mark = strlen(abuf);
X			}
X 			else if (mark > j) mark = j;
X			if (mark > 79) mark = 79;
X		}
X		xx = show_it( xx );
X		wrefresh( w4 );
X	} while ( ich != KEY_EXIT && ich != KEY_F( 6 ));
X	return;
X}					/* do_cmd() */
X
X/* The initialization sequences for the COMMAND mode. */
X
Xvoid cmd_disp()
X{
X	if (( log_fd = fopen("tst.log", "r" )) == NULL )
X	{
X		do_err( "Can't open \"tst.log\" for reading." );
X		return;
X	}
X	w4 = newwin( 0, 0, 0, 0 );
X	keypad( w4, TRUE );
X	sw4 = subwin( w4, LOGSZ , 80, 5, 0 );
X	scrollok( sw4, FALSE );
X	do_cmd();			/* This does the work */
X	fclose( log_fd );
X	wclear( sw4 );
X	wclear( w4 );
X	delwin( sw4 );
X	keypad( w4, FALSE );
X	wrefresh( w4 );
X	delwin( w4 );
X	refresh();
X	endwin();
X	return;
X}
END_OF_tstmodem.4.c
if test 19606 -ne `wc -c <tstmodem.4.c`; then
    echo shar: \"tstmodem.4.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 4 \(of 4\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Vernon C. Hoxie		       {ncar,nbires,boulder,isis}!scicom!zebra!vern
3975 W. 29th Ave.					voice: 303-477-1780
Denver, Colo., 80212				  TB+	 uucp: 303-455-2670