[net.micro.amiga] Picking a terminal emulator

wtm@neoucom.UUCP (07/14/86)

//////
	In response to the question about picking a terminal
emulator, I've been using the terminal program on the Digital
Creations "Gizmoz" disk.

	The Gizmoz terminal seems to be a very clean
implementation.  Most of the TVI 900 series termials are supported,
vt100, ansi, adm3a, etc. as well.  They seem to have done their
homework, as the vt100 works with unix/vi o.k.

	You've got to be careful.  A lot of terminal programs will
indeed generate the appropriate escape sequences, yet will not work
with vi because of slowness.  In particular, vi senses time delay
to tell if a human types <esc>-a or if an arrow key generated the
same code sequence.  I'm sure you can see that a slow emulator
could cause massive consternation!

	By the way, the terminal emulator is only one of many
interesting things on the Gizmoz disk.  Other interesting goodied
include a task scheduler, compress, crypt, etc.  The whole lot is
MSRP $49.95.  Probably the nicest disk I've actually purchased for
the amiga.  Also it is not!!! copy-protected.  Thanks!

	By the way, I tried Maxicomm, and it has time-out problems
with vi.  It is also copy-proof which severly limits its utility as
a program that you rely upon for day-to-day use.  (Sorry Maxicomm,
but that's how it is.)

	As you might have guessed, I don't work for either of these
companies.  There are several other emulators on the market as
well.  I think MSC has one.   My suggestion is to talk the
dealer in to letting you test it in the store with a modem.  Vi is
a good acid test.

Bill Mayhew
Div. Basic Sciences
NEOUCOM

cjp@vax135.UUCP (07/15/86)

Gizmoz is a good set of tools, but beware, its vt100 emulation
is not complete.  To wit, I wanted to play "larn" at home
via modem, but it doesn't work.  Probably the scrolling region
is unsupported.  For vi, it works fine.

oliver@unc.UUCP (07/16/86)

In article <232@neoucom.UUCP> wtm@neoucom.UUCP (Bill Mayhew) writes:
>//////
>	In response to the question about picking a terminal
>emulator, I've been using the terminal program on the Digital
>Creations "Gizmoz" disk.
>
>	The Gizmoz terminal seems to be a very clean
>implementation.  Most of the TVI 900 series termials are supported,
>vt100, ansi, adm3a, etc. as well.  They seem to have done their
>homework, as the vt100 works with unix/vi o.k.
>
>
>Bill Mayhew
>Div. Basic Sciences
>NEOUCOM


I have also enjoyed playing with my Gizmos, and have been using its
terminal program rather than Maxicomm because I can fit the
Gizmos emulator on my Workbench disk.  I can't say much about
how well it works on uploading and downloading since I only
use it to log on to the mainframe at work.  

I do have one question, however.  When I try to read news using
the Gizmos terminal emulator, I always lose the top line to the
title border.  Is there some command that I didn't see
in the documentation that will suppress the top border?

Thanks,

Bill Oliver

rjbj@hou2a.UUCP (07/17/86)

I also use the Gizmoz terminal emulator and I have found
that it does not completely emulate a vt100.  However,
the 920 terminal emulation is great and it works perfectly
with vi.

The only thing missing is xmodem file transfers.  Today,
I picked up On-Line by MICRO-SYSTEMS SIFTWARE, INC.  Although
the info on the package would never lead you to believe it,
it emulates a vt100, vt52, and an ansi terminal all of
which work great with vi.  In addition, it supports xmodem
and Compuserve B file transfer programs.  It cost about $60.00
and I am pleased so far.

papa@bacall.UUCP (Marco Papa) (07/17/86)

> //////
> 	In response to the question about picking a terminal
> emulator, I've been using the terminal program on the Digital
> Creations "Gizmoz" disk.
> 
> 	The Gizmoz terminal seems to be a very clean
> implementation.  Most of the TVI 900 series termials are supported,
> vt100, ansi, adm3a, etc. as well.  They seem to have done their
> homework, as the vt100 works with unix/vi o.k.
> 

We have currently in beta test version 1.1 of A-Talk that provides
emulations for VT100, VT52, Heath H19, ANSI, TTY, Televideo, and IBM3101
terminals.  Version 1.1 is scheduled for release around mid-August.
Together with the new emulations, Xmodem-CRC and Compuserve-B will be
supported (Xmodem Christensen and Kermit are supported in version 1.0).

> 	You've got to be careful.  A lot of terminal programs will
> indeed generate the appropriate escape sequences, yet will not work
> with vi because of slowness.  In particular, vi senses time delay
> to tell if a human types <esc>-a or if an arrow key generated the
> same code sequence.  I'm sure you can see that a slow emulator
> could cause massive consternation!

We have found that vi and emacs are good tests for emulators. Most terminal
programs will work fine, except when "fancy" features like scrolling are
used. Using "scroll-one-line-up" is an easy way to break Online! VT100
terminal emulator, for example.  Vi uses "scrolling" when pressing the down
arrow on the 24th line, which also will break a lot of emulators.  We are
looking for a few more folks that would like to beta test our version. We
are on a tight schedule, so if you are interested please contact me through
electronic mail.  Note that we have access to UNIX 4.2 and System V, and 
have tested the emulators with them already (using vi and emacs).

Marco Papa
Felsina Software
3175 South Hoover Street, #275
Los Angeles, CA 90007
(213)747-8498

P.S.:
Since Commodore advertised on the net about "their" VT100 emulator, and
nobody complained, it seems fair that everybody else should be able to do so.

bees@infoswx.UUCP (07/18/86)

>My suggestion is to talk the
>dealer in to letting you test it in the store with a modem.  Vi is
>a good acid test.

That's fine for 1200 or 2400, but what about 9600.  The friendly (ha!)
folks at Metropolitan Computer here in Richardson TX (hate, hate, spit,
fume, growl) won't let me try their AmigaTerm demo at work.  I refuse
to buy an emulator that won't keep up at close to 9600 baud.

This brings up a question to CBM:  why is it so stinking hard to get
fast emulation going on a 68000 box with a separate IOP!  It seems
a bit ridiculous to me... maybe the OS is really getting in the way?
Is the slowup all in the console driver?

Ray Davis

farmer@ico.UUCP (07/23/86)

>This brings up a question to CBM:  why is it so stinking hard to get
>fast emulation going on a 68000 box with a separate IOP!  It seems
>a bit ridiculous to me... maybe the OS is really getting in the way?
>Is the slowup all in the console driver?
Have you ever used a sun console?  It has a hard time doing 9600 baud -
doing bitmapped screens is expensive.  When someone is using the console,
the whole machine is slowed down dramaticly.  Of course the screen is
higher resolution.  I wouldn't blame the OS too much, look at how many times
you are doing translations when doing a terminal emulator.

Disclaimer:  Nobody will take responsibility for what I say, probably not
even me.

keithe@tekgvs.UUCP (Keith Ericson) (07/25/86)

In article <45100049@infoswx> bees@infoswx.UUCP writes:
>
>>My suggestion is to talk the
>>dealer in to letting you test it in the store with a modem.  Vi is
>>a good acid test.
>
>That's fine for 1200 or 2400, but what about 9600.  The friendly (ha!)
>folks at Metropolitan Computer here in Richardson TX (hate, hate, spit,
>fume, growl) won't let me try their AmigaTerm demo at work.  I refuse
>to buy an emulator that won't keep up at close to 9600 baud.
>
So get two amigas running, hook them together with a null-modem, fire
up the terminal emulator on both and send a file from one to the other
at 9600 (or whatever) baud and see if the receiving end can keep up.
(Or just copy a file to ser: from the transmitting end.)

keith

vanam@pttesac.UUCP (Marnix van Ammers) (07/30/86)

In article <18100001@ico> farmer@ico.UUCP writes:
>
>>This brings up a question to CBM:  why is it so stinking hard to get
>>fast emulation going on a 68000 box with a separate IOP!  It seems
>>a bit ridiculous to me... maybe the OS is really getting in the way?
>>Is the slowup all in the console driver?
>Have you ever used a sun console?  It has a hard time doing 9600 baud -
>doing bitmapped screens is expensive.  When someone is using the console,
>the whole machine is slowed down dramaticly.  Of course the screen is
>higher resolution.  I wouldn't blame the OS too much, look at how many times

About a month ago I bought Maxiterm from a local Computer Land
dealer.  It was Maxiterm V2.?  and it didn't work at all.  When
I called the company they said they'd send me their latest V3
dot something disk and that it would work.  I asked them if their
terminal program could keep up with 2400 baud since I knew that
the Online! program has a maximum throughput of 1100 baud.  They
said that their latest version kept up with 7200 baud.  The person
I was talking to also said that they had to go through quite a few
tricks to be able to do that.  I presume that he meant that they
had to bypass standard calls to the OS.  I think that's very
unfortunate.  I have a strong feeling that there is something
wrong with the OS if it looses characters at anything less than
9600.

By the way the newer Maxiterm works just fine.  I'm still not
sure I understand their requestor boxes when I try to capture
a file but that's probably my fault since I've misplaced my
documentation.  I've got a 2400 baud modem and Maxiterm keeps
up with it and that's my major concern.

As soon as I hear that Online! can handle 2400 baud, I'll
switch to it though because I love it's ability to do scripts.

What about it CBM?  Why are so many of the emulators unable to
keep up with a measily 1200 baud?  What do the Maxiterm people
know that the rest of us don't?

Marnix
-- 

dpz@topaz.RUTGERS.EDU (David P. Zimmerman) (08/02/86)

I got the Amiga C-Kermit and it does 9600 baud like a dream.  I use it
with the recently posted Amiga termcap (which seems to have a very
minor bug or two), and other than having to work within a 77x23 window
(to be fixed in a future release) I am quite happy.

				David
-- 
David P. Zimmerman		"Unix RULES!!!" - anonymous

Arpa: dpz@topaz.rutgers.edu
Uucp: ...{allegra | harvard | seismo | sri-iu | ut-sally}!topaz!dpz

gnu@hoptoad.uucp (John Gilmore) (08/04/86)

In article <18100001@ico>, farmer@ico.UUCP writes:
> >This brings up a question to CBM:  why is it so stinking hard to get
> >fast emulation going on a 68000 box with a separate IOP!
> Have you ever used a sun console?  It has a hard time doing 9600 baud -
> doing bitmapped screens is expensive.  When someone is using the console,
> the whole machine is slowed down dramaticly.  Of course the screen is
> higher resolution.

I wrote the original Sun console driver.  It's actually pretty fast to
write characters up on the screen; for example, vnews or "page" is very
fast.  The slow part is scrolling -- you have to move about 128K of
memory for each scroll (1152 x 900 = a million bits of image).  The
trick I finally settled on is that anytime I had to scroll the screen,
I would look ahead in the data stream and count up how many lines of
data were there, and scroll that many in one leap.  This looks a little
odd on the screen until you get used to it, but it lets the console run
at very high speeds (9600 forever when running standalone at the time;
I haven't measured it in years).

Of course, your terminal emulator, window system, application program,
or whatever must be smart enough to buffer up chunks of stuff to send
to the screen, so that when it looks ahead it will find several lines
of stuff.  (This also cuts down on the function call/system call
overhead of passing the data around.) In particular, when emulating a
terminal over a serial port, you have to use interrupts to grab the
received characters; if you poll, moving that 128K will cause big gaps
in the polling and you will drop chars.  I used a simple circular buffer
that the interrupt routine would just drop chars into; the mainline
code did nothing but look in the buffer all the time.  Anytime it found
new data, it would send ALL the new data to the screen.  By the time
the screen painting code returned, there would often be another block
of new data, etc.

The Amiga should be able to cope with fast serial lines with similar
methods.
-- 
John Gilmore  {sun,ptsfa,lll-crg,ihnp4}!hoptoad!gnu   jgilmore@lll-crg.arpa
		     May the Source be with you!

daveh@cbmvax.cbm.UUCP (Dave Haynie) (08/04/86)

> What about it CBM?  Why are so many of the emulators unable to
> keep up with a measily 1200 baud?  What do the Maxiterm people
> know that the rest of us don't?
> 
> Marnix
> -- 

I've had no trouble running AmigaTerm (not out yet, will be sold with the
1680 modem from C-A) or StarTerm 3.0 (PD by Jim Nangano on CIS) at 9600
baud with the VAX system here.  AmigaTerm even did the VT100 emulation
properly.  One thing to consider is to cut down on the number of bit planes
in your screen -- a screen with 1 bit plane will ideally run twice as fast
as a screen with two.  Though StarTerm 3.0, apparently the faster of the
two (though I've never run above 9600 Baud) uses the normal Workbench
colors, 2 bit-planes.

-- 
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
Dave Haynie    {caip,ihnp4,allegra,seismo}!cbmvax!daveh

	"I don't feel safe in this world no more, 
	 I don't want to die in a nuclear war,
	 I want to sail away to a distant shore
	 And live like an ape man."
				-The Kinks

	These opinions are my own, though for a small fee they be yours too.
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

jal@tiger.UUCP (08/06/86)

I have been using the Online! terminal emulator for some time 
now and I have had a lot of problems with "vi".  I am getting
ready to compile "kermit".  I understand that it has a vt100
emulation built in.


nevermindthefurthermorethepleaisselfdefencenevermindthefurthermorethepleaisself
				|
   NAME:  J. Allen Schones	| DISCLAIMER:
ADDRESS:  AT&T Technologies	|             1) I didn't write this.
          7725 W. Reno		|	      2) You didn't read this.
	  Oklahoma City, OK	|	      3) My company doesn't think.
	  73125			|	All Disclaimers are disclaimed.
   UUCP:  inhp4!occrsh!tiger!jal|
 MABELL:  (405)-491-4950	|
				|
defencenevermindthefurthermorethepleaisselfdefencenevermindthefurthermoretheple

	My Mistress is pooped,
	the Reds have Oklahoma,
	and I'm going to bed.
			- Hodge Podge -
			(Penguin Dreams...)

andy@amiga.UUCP (Andy Finkel) (08/07/86)

In article <253@pttesac.UUCP> vanam@pttesac.UUCP (Marnix van Ammers) writes:
>In article <18100001@ico> farmer@ico.UUCP writes:
>>
>>>This brings up a question to CBM:  why is it so stinking hard to get
>>>fast emulation going on a 68000 box with a separate IOP!  It seems
>>>a bit ridiculous to me... maybe the OS is really getting in the way?
>>>Is the slowup all in the console driver?
>>Have you ever used a sun console?  It has a hard time doing 9600 baud -
>>doing bitmapped screens is expensive.  When someone is using the console,
>>the whole machine is slowed down dramaticly.  Of course the screen is
>>higher resolution.  I wouldn't blame the OS too much, look at how many times
>
>What about it CBM?  Why are so many of the emulators unable to
>keep up with a measily 1200 baud?  What do the Maxiterm people
>know that the rest of us don't?
>
>Marnix
>-- 

There are (at least) three things a terminal program should do that help 
keep up at 9600 baud...

1) Use the SDCMD_QUERY for the serial device, to find out how many
   characters the device has waiting, then get exactly that number.

2) Use the console device, and when sending characters to the screen,
   send as many as possible.  (keep a buffer)  This also allows you
   to do multiple line scrolling tricks (a la Gilmore & Sun) if you've
   got a number of line feeds stored in the buffer.

3) Use a 1 bit plane screen.  2+ bitplanes don't show down text
   very much (especially if you write in JAM1), but for scrolling,
   1 bit plane is a big win.

4) Do your serial I/O async style (use SendIO) and use 2 ports
   (one for read, one for write)

(see, I said that there were at least three...)

AmigaTerm (our terminal program, soon to be shipped with the modem
for the Amiga, and maybe seperately) has a slightly higher throughput
than a DEC VT101 (but slightly lower than a CIT-101).

			andy


-- 

			andy finkel
			Commodore(Amiga)
			{ihnp4|seismo|allegra}!cbmvax!andy
		or	 pyramid!amiga!andy

Any expressed opinions are mine; but feel free to share.

I disclaim all responsibilities, all shapes, all sizes, all colors.

"Remember, no matter where you grow, there you are." - Buckaroo Bonsai.

swalton@well.UUCP (Stephen R. Walton) (08/08/86)

In article <1474@amiga.amiga.UUCP> andy@skipper.UUCP (andy finkel) writes:
>1) Use the SDCMD_QUERY for the serial device, to find out how many
>   characters the device has waiting, then get exactly that number.
>

Do you mean that I can open up my ports to the serial device and do an
SDCMD_QUERY without having done a SendIO or DoIO first, and it will tell
me how many characters it has in its read buffer?

>AmigaTerm (our terminal program, soon to be shipped with the modem
>for the Amiga, and maybe seperately) has a slightly higher throughput
>than a DEC VT101 (but slightly lower than a CIT-101).

I'm not sure this is all that impressive (sorry, Andy).  A VT100 has only
a 64 character buffer, which fills up pretty quickly at 9600 baud.  The
real question is, what is the maximum baud rate for which AmigaTerm doesn't
need flow control?

Steve Walton

dpz@topaz.RUTGERS.EDU (David P. Zimmerman) (08/12/86)

> I have been using the Online! terminal emulator for some time 
> now and I have had a lot of problems with "vi".  I am getting
> ready to compile "kermit".  I understand that it has a vt100
> emulation built in.

Kermit unfortunately does not have VT100 emulation built in.  It uses
console.device, so if you want terminal emulation with it, you'd
probably want to pick up an Amiga termcap.

				^D
-- 
David P. Zimmerman		"Unix RULES!!!" - anonymous

Arpa: dpz@topaz.rutgers.edu
Uucp: ...{allegra | harvard | seismo | sri-iu | ut-sally}!topaz!dpz

andy@amiga.UUCP (Andy Finkel) (08/12/86)

In article <1602@well.UUCP> swalton@well.UUCP (Stephen R. Walton) writes:
>In article <1474@amiga.amiga.UUCP> andy@skipper.UUCP (andy finkel) writes:
>>1) Use the SDCMD_QUERY for the serial device, to find out how many
>>   characters the device has waiting, then get exactly that number.
>>
>
>Do you mean that I can open up my ports to the serial device and do an
>SDCMD_QUERY without having done a SendIO or DoIO first, and it will tell
>me how many characters it has in its read buffer?
>
Well, actually you send the SDCMD_QUERY to the serial device by a
DoIO or SendIO.  This is generally how you communicate with devices
on the Amiga.

>The real question is, what is the maximum baud rate for which AmigaTerm 
>doesn't need flow control?
>
>Steve Walton

It was measured at between 9100 and 9200 baud.

			andy finkel
-- 

			andy finkel
			Commodore(Amiga)
			{ihnp4|seismo|allegra}!cbmvax!andy
		or	 pyramid!amiga!andy

Any expressed opinions are mine; but feel free to share.

I disclaim all responsibilities, all shapes, all sizes, all colors.

"Remember, no matter where you grow, there you are." - Buckaroo Bonsai.

hamilton@uiucuxc.CSO.UIUC.EDU (08/13/86)

>>1) Use the SDCMD_QUERY for the serial device, to find out how many
>>   characters the device has waiting, then get exactly that number.
>>
>
>Do you mean that I can open up my ports to the serial device and do an
>SDCMD_QUERY without having done a SendIO or DoIO first, and it will tell
>me how many characters it has in its read buffer?

    SDCMD_QUERY is an i/o command just like READ, WRITE, or SETPARAMS,
so you would do a DoIO() with io_Command = SDCMD_QUERY.  the resulting
io_Actual is the number of bytes ready to read (like ioctl FIONREAD,
if you know what i mean).

>>AmigaTerm (our terminal program, soon to be shipped with the modem
>>for the Amiga, and maybe seperately) has a slightly higher throughput
>>than a DEC VT101 (but slightly lower than a CIT-101).
>
>I'm not sure this is all that impressive (sorry, Andy).  A VT100 has only
>a 64 character buffer, which fills up pretty quickly at 9600 baud.  The
>real question is, what is the maximum baud rate for which AmigaTerm doesn't
>need flow control?

    that could depend... unlike the vt100, the amiga has many kilobytes
available for buffering.  use enough, and even long bursts of data won't
overrun before statistics average the rate down.  just set the io_RBufLen
field while you're setting baud rate, etc, in a SDCMD_SETPARAMS.  default
is 512, so there's plenty of room for improvement there.

	wayne hamilton
	U of Il and US Army Corps of Engineers CERL
UUCP:	{ihnp4,pur-ee,convex}!uiucdcs!uiucuxc!hamilton
ARPA:	hamilton%uiucuxc@a.cs.uiuc.edu	USMail:	Box 476, Urbana, IL 61801
CSNET:	hamilton%uiucuxc@uiuc.csnet	Phone:	(217)333-8703
CIS:    [73047,544]			PLink: w hamilton

daveb@cbmvax.cbm.UUCP (Dave Berezowski) (08/16/86)

> >>AmigaTerm (our terminal program, soon to be shipped with the modem
> >>for the Amiga, and maybe seperately) has a slightly higher throughput
> >>than a DEC VT101 (but slightly lower than a CIT-101).
> >
> >I'm not sure this is all that impressive (sorry, Andy).  A VT100 has only
> >a 64 character buffer, which fills up pretty quickly at 9600 baud.  The
> >real question is, what is the maximum baud rate for which AmigaTerm doesn't
> >need flow control?
> 
>     that could depend... unlike the vt100, the amiga has many kilobytes
> available for buffering.  use enough, and even long bursts of data won't
> overrun before statistics average the rate down.  just set the io_RBufLen
> field while you're setting baud rate, etc, in a SDCMD_SETPARAMS.  default
> is 512, so there's plenty of room for improvement there.
> 

	Under v1.1, AmigaTerm had a measured throughput of approx
9100-9200 baud. I don't know what it will be under 1.2 but since 1.2
has faster text output it should be at least this fast. What Andy meant
by the VT100 - CIT-101e comment was that if you put a VT100, AmigaTerm,
and a CIT-101 beside each other and say 'cat' some text to it; the CIT-101
will finish first, then AmigaTerm, then the VT100.

	You comment regarding using a super large buffer bears some discussion.
What happens when you xoff the host? Does the terminal program xoff the host and
then a)empty its buffer or b)halt output to the screen immediately. If you chose
'a' and you have a very large buffer (say >= 1K) then a delayed effect is produced
which makes the user think that the xoff didn't work. (You know, the user hits
xoff, but 1K of data gets printed after that.)  Method b solves the above problem
but in a way gets you out of sync with the host. If a user xoff's the host and
then decides to abort the output altogether (lets say with a ctrl-c to the host)
the user will still get the 1K of data that's in the local buffer.

	VT100's and CIT-101's get around this problem by using method 'a' and
a relatively small buffer (as you  mentioned, only 64 bytes). Since the smallest
buffer possible is 512 bytes (when using the serial device) AmigaTerm (under 1.1)
uses method 'b' as beta-testers found method 'a' un-acceptable.

	I don't know what method the final released version of AmigaTerm uses
as 1.2 enhancements/bug fixes were made after I left CBM. I should also mention
that beta-testers and myself found little difference (if any) using a CIT-101
or AmigaTerm at 9600 baud (ie. 400 out of 9600 baud [a 4% difference] is not
easy for a human to notice under most conditions).

	Besides throughput speed, the other features that may make AmigaTerm
desirable are:

	a) full support of ALL VT100 character sets
	   (US, UK, graphics, special graphics, extended gfx, vt52, vt52 gfx).'
	b) a 128 column (with the above true as well) which under most
	   conditions operates as well as 132 columns.
	c) 24(non-interlace) or 49(interlace) lines.
	d) full VT100 emulation (with the exception of blinking LED support,
	  (double height/width characters, etc).
	  (ie. it was tested with emacs, vi, edt, etc).

	Hope this helps.

	Regards, David Berezowski

Disclaimer: I no longer work for CBM and my comments are products of
	sparatic movements by my fingers.

mic@ut-ngp.UUCP (Mic Kaczmarczik) (08/20/86)

   The following is a modified version of the Amigaterm terminal
emulator written by Michael Mounier in the distant past (ca. last
winter).  This program has no relation (except in function) to the
Amigaterm terminal emulator soon to be marketed by Commodore-Amiga.

   The program was compiled with Lattice C version 3.03.  There's
just one source file, so compile it and link with Lstartup.obj
and amiga.lib.

   "Awright, who needs another version of Amigaterm???", you ask.
Well, I'm posting this because it gives an example of 1) connecting
the console device to a window, and 2) using the serial command
SDCMD_QUERY to read in as many characters as possible at a time
from the serial port, which makes it *MUCH* faster!

   Using this program, I've managed to keep up with page after page
of 80-column lines at 9600 baud, although sending an XOFF to the host
takes a while to have any apparent effect at such high speeds.  It's
also nice to have an 80-column window, full-screen editing...

   Enjoy,

   Mic Kaczmarczik

   UUCP:   ...!ihnp4!seismo!ut-sally!ut-ngp!mic
   ARPA:   mic@a20.cc.utexas.edu
   BITNET: ccep001@utadnx.bitnet

--------If you don't cut here, you'll see lots of compilation errors------
/*
 *  AmigaTerm!
 *
 *  A terminal program that has ascii and xmodem transfer capability
 *
 *  Use ESC to abort xmodem transfer
 *
 *  Written by Michael Mounier
 *
 *  Console stuff, quit, preference items (and serious hacking trying to
 *  improve throughput) by Mic Kaczmarczik
 *
 *  Thrust into the harsh light of public scrutiny August 19, 1986
 */

#include <exec/types.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <devices/serial.h>
#include <devices/keymap.h>
#include <devices/inputevent.h>
#include <stdio.h>
#include <ctype.h>
#include <libraries/dos.h>

/* specify which revision level of the Graphics and Intuition
 * libraries we'll settle for
 */
#define INTUITION_REV 1
#define GRAPHICS_REV  1

/* things for xmodem send and recieve */
#define SECSIZ   0x80
#define TTIME    30	/* number of seconds for timeout */
#define BufSize  0x1000	/* Text buffer */
#define ERRORMAX 10	/* Max errors before abort */
#define RETRYMAX 10	/* Maximum retrys before abort */
#define SOH      1	/* Start of sector char */
#define EOT      4	/* end of transmission char */
#define ACK      6	/* acknowledge sector transmission */
#define NAK      21	/* error in transmission detected */

/* New window structure */
struct NewWindow NewWindow = {
   0, 0, 640, 200,
   0, 1,
   CLOSEWINDOW | MENUPICK,
   WINDOWCLOSE | SMART_REFRESH | ACTIVATE |
	BORDERLESS | WINDOWDEPTH,
   NULL,
   NULL,
   "AmigaTerm 1.7(6)",
   NULL,
   NULL,
   160, 50, 640, 200,
   WBENCHSCREEN,
};

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Window *mywindow;             /* ptr to applications window */
struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */

/***************************************************/
/*               Main Menu Definition              */
/*                                                 */
/*      This section of code is where the simple   */
/*   menu definition goes.                         */
/***************************************************/

/* Number of available menu topics */
#define MAXMENU 3
struct Menu menu[MAXMENU];

#define FILEMAX 5
struct MenuItem FileItem[FILEMAX];
struct IntuiText FileText[FILEMAX];

#define SETMAX 3
struct MenuItem SetItem[SETMAX];
struct IntuiText SetText[SETMAX];

#define TWMAX 5
struct MenuItem TWItem[TWMAX];
struct IntuiText TWText[TWMAX];

/*****************************************************/
/*                Settings submenus                  */
/*****************************************************/

/* BaudRate submenu */
#define RSMAX 6
struct MenuItem RSItem[RSMAX];
struct IntuiText RSText[RSMAX];
int baudrates[RSMAX] = { 300, 450, 1200, 2400, 4800, 9600 };
char *baudstrings[RSMAX] = {
	"   300",
	"   450",
	"   1200",
	"   2400",
	"   4800",
	"   9600" };

/* Parity submenu */
#define PSMAX 3
struct MenuItem PSItem[RSMAX];
struct IntuiText PSText[RSMAX];

/* Byte length submenu */
#define BSMAX 2
struct MenuItem BSItem[BSMAX];
struct IntuiText BSText[BSMAX];


/* Flags for various preferences.
 * This lack of structure is not good for later improvements :-)
 *
 * bs_to_del -- map BS to DEL and DEL to BS
 * echo      -- local echo
 * wrap	     -- line wrap (nice for small terminal windows)
 * newline   -- console interprets \n as \r\n?
 * debug     -- show how bad our throughput is
 */

int bs_to_del = 1;	/* BS -> DEL	*/
int echo      = 0;	/* local echo	*/
int wrap      = 1;	/* auto wrap	*/
int newline   = 1;	/* console NL acts like CR + NL*/
int debug     = 0;	/* put '|' around each modem read */

/***********************************************
 	declarations for the serial stuff
 ***********************************************/

extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();

struct IOExtSer *Read_Request;
struct IOExtSer *Write_Request;
unsigned char	ser_in[BufSize],		/* serial input buffer	*/
		ser_out[2],			/* serial output buffer */
		capbuf[BufSize];		/* capture buffer	*/

int  fd, timeout = FALSE;
long bytes_xferred;

/*******************************************
	 Declarations for console device
 *******************************************/

struct IOStdReq *consoleWriteMsg;	/* I/O request block pointer */
struct IOStdReq *consoleReadMsg;	/* Ditto */
struct MsgPort *consoleWritePort;	/* port at which to receive replies*/
struct MsgPort *consoleReadPort;	/* ditto */
unsigned char	con_in[1],		/* Buffer for console read */
		con_out[BufSize];	/* Ditto for console write */

/****************************************************
		Error handling
 ****************************************************/

#define	ERR_INTUITIONBASE	1
#define	ERR_GFXBASE		2
#define	ERR_NEWWINDOW		3
#define ERR_ALLOC_READ_REQ	4
#define	ERR_CRE_READ_PORT	5
#define	ERR_OPEN_SER_READ	6
#define	ERR_ALLOC_WRITE_REQ	7
#define	ERR_OPEN_SER_WRITE	8
#define	ERR_CRE_WRITE_PORT	9
#define	ERR_CRE_CON_WRITE	10
#define	ERR_CRE_STD_WRITE	11
#define ERR_CRE_CON_READ	12
#define ERR_CRE_STD_READ	13
#define ERR_OPENCONSOLE		14


#define SERIAL_CHAR (1<<ReadBit)
#define TYPED_CHAR (1<<ConsoleBit)
#define INTUITION_EVENT (1<<IntuitionBit)

/******************************************************/
/*                   Main Program                     */
/******************************************************/

/*
 * Variables that used to be local to the main program
 * before I put almost everything in separate routines
 */

unsigned char c, name[32];
ULONG class;
USHORT code, menunum, itemnum, subnum;
int KeepGoing, EventMask, capture, send;
FILE *tranr = NULL, *trans = NULL;

int ReadBit, IntuitionBit, ConsoleBit;

static char *announce[] = {
"\f\x9b7m",
"                         Amigaterm 1.7(6",
") 19-Aug-1986                           ",
"\r\n",
"     Written by Michael Mounier, *seriou",
"sly* hacked up by Mic Kaczmarczik       ",
"\r\n\x9b0m",
(char *) 0 };

main()
{
	char **msg;

	/*
	 * Set up the display
	 */

	OpenUpWindows();
	OpenUpSerial();
	OpenUpConsole();

	/*
	 * Set screen length to 24 lines. This messes up Intuition's
	 * title bar and gadgets, but 24 lines is worth it, right?
	 */

	emits("\23324\164");	/* set 24 lines/page */
	emits("\2330\171");	/* set window offset 0 */
	for (msg = &announce[0]; *msg; msg++)
		emits(*msg);

	InitFileItems();	/* File menu		*/
	  InitRSItems();
	  InitPSItems();
	  InitBSItems();
	InitSetItems();		/* Settings menu	*/
	InitTweakItems();	/* Tweak menu		*/
	InitMenu();		/* Set up menu		*/
	SetMenuStrip(mywindow,&menu[0]);

	/*
	 * Initialize flags
	 */

	KeepGoing = TRUE;
	capture = FALSE;
	send = FALSE;

	/*
 	 * Intuition messages
	 */
	ReadBit = Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit;
	IntuitionBit = mywindow->UserPort->mp_SigBit;
	ConsoleBit = consoleReadPort->mp_SigBit;
	
	/*
	 * Queue up reads to the serial and console devices
	 */
	SendIO(Read_Request);
	SendIO(consoleReadMsg);

	/*
	 * Main event loop
	 */
	while( KeepGoing ) {
		/* wait for window, console, or serial port message */
		EventMask = Wait(SERIAL_CHAR | TYPED_CHAR | INTUITION_EVENT);

		if (CheckIO(Read_Request))		/* serial char	*/
			Handle_Modem();

 		if (EventMask & TYPED_CHAR)		/* from keyboard */
			Handle_Char();

		/* Intuition events */
		while (NewMessage = (struct IntuiMessage *)
						GetMsg(mywindow->UserPort)) {
			class = NewMessage->Class;
			code = NewMessage->Code;
			ReplyMsg( NewMessage );

			switch (class) {
			case CLOSEWINDOW:
		          /* User is ready to quit, so indicate that
			   * execution should terminate with next
			   * iteration of the loop.
		           */
		                KeepGoing = FALSE;
		                break;
		        case MENUPICK:
				if (code == MENUNULL)
					break;
				menunum = MENUNUM(code);
				itemnum = ITEMNUM(code);
				subnum = SUBNUM(code);
				switch (menunum) {
				case 0:		/* File Menu */
					DoFileMenu(itemnum);
					break;			
		                case 1: 	/* Settings menu */
					switch (itemnum) {
					case 0:
						DoBaudRateMenu(subnum);
						break;
					case 1:
						DoParityMenu(subnum);
						break;
					case 2:
						DoByteMenu(subnum);
						break;
					}
			                break;
				case 2:		/* Tweak menu */
					DoTweakMenu(itemnum);
					break;
		                } /* switch (menunum) */
			}   /* switch (class) */
		}   /* while (newmessage) */
	}  /* while (keepgoing) */

	/*   It must be time to quit, so we clean up and exit. */
	cleanup(0);
}

/*
 * Called when CheckIO() has returned true in main program.
 * Since this routine has a large impact on throughput, there's
 * lots of spaghetti and speed optimization -- some of which might
 * actually work (?).
 */

Handle_Modem()
{
	unsigned char ch;
	register struct IOStdReq *request;
	register unsigned char *cp, *obufp, *top;

	/* we use Read_Request->IOSer a lot, so cache it in a register */

	request = &Read_Request->IOSer;

	/* complete the read and buffer the character	*/

	WaitIO(Read_Request);
	obufp = con_out;
	if ((ch = (ser_in[0] & 0x7F)) && (ch != 0x7F)) {
		if (debug)
			*(obufp++) = '|';
		*(obufp++) = ch;
	}

	/* peek into the serial buffer for more characters */
	request->io_Command = SDCMD_QUERY;
	DoIO(Read_Request);
	request->io_Command = CMD_READ;	/* eager... */
	
	/* got some? if so, copy into the buffer, filtering as we go */
	if (request->io_Actual > 0L) {
		request->io_Length = request->io_Actual;
		DoIO(Read_Request);
		top = ser_in + request->io_Actual;
		for (cp = ser_in; cp < top; cp++)
			if ((*cp &= 0x7F) && (*cp != 0x7F))
				*(obufp++) = *cp;
	}

	if (debug)
		*(obufp++) = '}';

	/* requeue read request */
	request->io_Length = (ULONG) 1;
	SendIO(Read_Request);

	/* put the character(s) on the screen */
	consoleWriteMsg->io_Length = (LONG) (obufp - con_out);
	consoleWriteMsg->io_Data = (APTR) con_out;
	DoIO(consoleWriteMsg);

	/* Ascii capture (always slower than not doing it) */
	if (capture)
		for (cp = con_out; cp < obufp; cp++)
			fputc(*cp, tranr);
}

/*
 * Respond to a typed character
 */

Handle_Char()
{
	GetMsg(consoleReadPort);
	/* Handle command sequence introducer */
	if ((con_in[0] & 0xFF) == 0x9B) {
		ser_out[0] = 0x1B;
		DoIO(Write_Request);
		if (echo)
			emit(ser_out[0]);
		con_in[0] = '[';
	}
	if (bs_to_del) {
		if (con_in[0] == '\b')
			con_in[0] = 0177;
		else if (con_in[0] == 0177)
			con_in[0] = '\b';
	}
	ser_out[0] = con_in[0];

	/* Requeue read AFTER done with con_in!! */
	SendIO(consoleReadMsg);
	DoIO(Write_Request);
	if (echo) {
		emit(ser_out[0]);
		if (capture)
			fputc(ser_out[0], tranr);
	}
}

/*
 * Implement File menu commands
 */

DoFileMenu(ItemNumber)
USHORT ItemNumber;
{
	switch( ItemNumber ) {
	case 0: /* Ascii receive */
		if (capture) {
	        	capture = FALSE;
		        fclose(tranr);
		        emits("\r\nEnd File Capture\r\n");
                }
		else {
                        emits("\r\nAscii Capture:");
                        filename(name);
	    	        if (!strlen(name))
			        break;
	                if ((tranr = fopen(name,"w")) == NULL) {
	                	capture=FALSE;
	                        emits("\r\nError Opening File\r\n");
	                        break;
	                }
	                capture = TRUE;
	        }
	        break;
	case 1: /* Ascii send */
		emits("\r\nAscii Send:");
		filename(name);
		if (!strlen(name))
			break;
		emits("\r\nType ESC to abort\r\n");
		if ((trans=fopen(name,"r")) == NULL) {
			emits("\r\nError Opening File\r\n");
			break;
		}
		Ascii_Send(trans);
		fclose(trans);
		emits("\r\nSend completed\r\n");
	        break;
	case 2: /* Xmodem recieve */
		emits("\r\nXmodem Receive:");
		filename(name);
		if (!strlen(name))
			break;
	        if (XMODEM_Read_File(name))
			emits("\r\nRecieved File\r\n");
	        else {
			close(fd);
	                emits("Xmodem Receive Failed\r\n");
	        }
	        break;
	case 3: /* Xmodem send */
                emits("\r\nXmodem Send:");
                filename(name);
		if (!strlen(name))
			break;
                if (XMODEM_Send_File(name))
                	emits("\r\nSent File\r\n");
                else {
                        close(fd);
                        emits("\r\nXmodem Send Failed\r\n");
                }
                break;
	case 4:	/* Quit */
	       KeepGoing = 0;	/* Quit after last message*/
	       break;
	} /* Switch (file item menu number) */
	return (0);
} /* DoFileMenu */

/*
 * Implement BaudRate menu
 */

DoBaudRateMenu(ItemNumber)
USHORT ItemNumber;
{
	AbortIO(Read_Request);
	Read_Request->io_Baud = baudrates[ItemNumber];
	setparams(Read_Request);
	return (0);
} /* DoBaudRateMenu */

/*
 * Ditto mit der tveek menu...
 */

DoTweakMenu(ItemNumber)
USHORT ItemNumber;
{
	switch(ItemNumber) {
	case 0:	/* BS <-> DEL */
		set_toggle(bs_to_del = !bs_to_del,&TWItem[ItemNumber].Flags);
		break;
	case 1: /* local echo */
		set_toggle(echo = !echo,&TWItem[ItemNumber].Flags);
		break;
	case 2: /* auto wrap */
		set_toggle(wrap = !wrap,&TWItem[ItemNumber].Flags);
		emits(wrap ? "\x9B?7h" : "\x9B?7l");
		break;
	case 3: /* newline */
		set_toggle(newline = !newline,&TWItem[ItemNumber].Flags);
		emits(newline ? "\x9b20h" : "\x9b20l");
		break;
	case 4: /* debug */
		set_toggle(debug = !debug,&TWItem[ItemNumber].Flags);
		break;
	} /* switch */
	return (0);
}

/*
 * Parity setting menu (wot a gross hack)
 */

DoParityMenu(ItemNumber)
USHORT ItemNumber;
{
	AbortIO(Read_Request);
	switch(ItemNumber) {
	case 0:		/* none -- clear "parity on" flag */
		Read_Request->io_SerFlags &=
			~(SERF_PARTY_ON | SERF_PARTY_ODD);
		break;
	case 1:		/* even parity -- clear ODD bit, turn parity on*/
		Read_Request->io_SerFlags |= SERF_PARTY_ON;
		Read_Request->io_SerFlags &= ~SERF_PARTY_ODD;
		break;
	case 2:		/* odd -- set ODD bit, turn parity on */
		Read_Request->io_SerFlags |= 
			SERF_PARTY_ON | SERF_PARTY_ODD;
		break;
	}
	setparams(Read_Request);	/* set 'em, go back to reading */
	return 0;
} /* DoParityMenu */

/*
 * Byte length menu
 */

DoByteMenu(ItemNumber)
USHORT ItemNumber;
{
	AbortIO(Read_Request);
	switch(ItemNumber) {
	case 0:		/* 7 bit bytes */
		Read_Request->io_ReadLen = 7;
		Read_Request->io_WriteLen = 7;
		break;
	case 1:		/* 8 bit bytes */
		Read_Request->io_ReadLen = 8;
		Read_Request->io_WriteLen = 8;
		break;
	}
	setparams(Read_Request);
	return 0;
} /* DoParityMenu */

/*
 * Set the CHECKED bit of a MenuItem's Flags field. I suspect
 * this could be avoided if I understood the MutualExclude field
 * a little better...
 */
set_toggle(onoff,flgp)
int onoff;
USHORT *flgp;
{
	*flgp = onoff ? (*flgp | CHECKED) : (*flgp & ~CHECKED);
}

/*
 * Reset the parameters on the serial device, then return
 * it to "READ" state and queue the next read.
 */

setparams(Read_Request)
struct IOExtSer *Read_Request;
{
	Read_Request->IOSer.io_Command = SDCMD_SETPARAMS;
        DoIO(Read_Request);

	/* Reset read_request to read again */
	Read_Request->IOSer.io_Command = CMD_READ;
	SendIO(Read_Request);
	return (0);
}

/*****************************************************************
 *		
 *		Initialization And Cleanup
 *
 *****************************************************************/
/*
 * Open windows and Intuition
 */

OpenUpWindows()
{
	IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library", INTUITION_REV);
	if( IntuitionBase == NULL )
		cleanup(ERR_INTUITIONBASE);

	GfxBase = (struct GfxBase *)
		OpenLibrary("graphics.library",GRAPHICS_REV);
	if( GfxBase == NULL ) cleanup(ERR_GFXBASE);

	if(( mywindow = (struct Window *) OpenWindow(&NewWindow) ) == NULL)
		cleanup(ERR_NEWWINDOW);
}

/*
 * Open serial device and initialize things
 */
 
OpenUpSerial()
{
	Read_Request = (struct IOExtSer *)
		AllocMem(sizeof(*Read_Request),MEMF_PUBLIC|MEMF_CLEAR);
	if (Read_Request == NULL) cleanup(ERR_ALLOC_READ_REQ);

	Read_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
	Read_Request->IOSer.io_Message.mn_ReplyPort =
		CreatePort("Read_RS",0);
	if (Read_Request->IOSer.io_Message.mn_ReplyPort == 0)
		cleanup(ERR_CRE_READ_PORT);
	if(OpenDevice(SERIALNAME,NULL,Read_Request,NULL))
		cleanup(ERR_OPEN_SER_READ);

	Read_Request->IOSer.io_Command = CMD_READ;
	Read_Request->IOSer.io_Length = 1;
	Read_Request->IOSer.io_Data = (APTR) &ser_in[0];

	Write_Request = (struct IOExtSer *)
		AllocMem(sizeof(*Write_Request),MEMF_PUBLIC|MEMF_CLEAR);
	if (Write_Request == NULL) cleanup(ERR_ALLOC_WRITE_REQ);

	Write_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
	Write_Request->IOSer.io_Message.mn_ReplyPort = 
		CreatePort("Write_RS",0);
	if (!Write_Request->IOSer.io_Message.mn_ReplyPort)
		cleanup(ERR_CRE_WRITE_PORT);
	if(OpenDevice(SERIALNAME,NULL,Write_Request,NULL))
		cleanup(ERR_OPEN_SER_WRITE);

	Write_Request->IOSer.io_Command = CMD_WRITE;
	Write_Request->IOSer.io_Length = 1;
	Write_Request->IOSer.io_Data = (APTR) &ser_out[0];

	Read_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
	Read_Request->io_Baud = 1200;
	Read_Request->io_ReadLen = 8;
	Read_Request->io_WriteLen = 8;
	Read_Request->io_StopBits = 1;
	Read_Request->io_CtlChar = 1L;
	Read_Request->io_RBufLen = 1024;	/* bigger buffer */
	Read_Request->IOSer.io_Command = SDCMD_SETPARAMS;
	DoIO(Read_Request);
	Read_Request->IOSer.io_Command = CMD_READ;
} /* OpenUpSerial() */

/*
 * Open up console device stuff
 */

OpenUpConsole()
{
	if ((consoleWritePort = CreatePort("Write_Con",0)) == 0)
		cleanup(ERR_CRE_CON_WRITE);
	if ((consoleWriteMsg = CreateStdIO(consoleWritePort)) == 0)
		cleanup(ERR_CRE_STD_WRITE);
	if ((consoleReadPort = CreatePort("Read_Con",0)) == 0)
		cleanup(ERR_CRE_CON_READ);
	if ((consoleReadMsg = CreateStdIO(consoleReadPort)) == 0)
		cleanup(ERR_CRE_STD_READ);
	if (OpenConsoleW(consoleWriteMsg,consoleReadMsg,mywindow))
		cleanup(ERR_OPENCONSOLE);
	consoleWriteMsg->io_Command = CMD_WRITE;
	consoleReadMsg->io_Command = CMD_READ;
	consoleReadMsg->io_Data = (APTR) &con_in[0];
	consoleReadMsg->io_Length = 1;
} /* OpenUpConsole */

/*
 * Release system resources in the order they were allocated.  It's
 * organized as sort of a jump table so we can 'jump'
 * into the correct part of the cleanup code.
 * Things like this are ****REALLY**** dependent on the way code gets
 * called in the main program, so perhaps a better approach would be to 
 * use a bit mask, one bit for each allocated resource.   Maybe even a
 * number of bit masks, one for each type of resource (menus, windows,
 * serial, console, etc).
 */
 
cleanup(error)
int error;
{
	switch (error) {
	case 0:	/* Everything... */
		ClearMenuStrip(mywindow);
		CloseDevice(consoleWriteMsg);
	case ERR_OPENCONSOLE:
		DeleteStdIO(consoleReadMsg);
	case ERR_CRE_STD_READ:
		DeletePort(consoleReadPort);
	case ERR_CRE_CON_READ:
		DeleteStdIO(consoleWriteMsg);
	case ERR_CRE_STD_WRITE:
		DeletePort(consoleWritePort);
	case ERR_CRE_CON_WRITE:
		CloseDevice(Write_Request);
	case ERR_CRE_WRITE_PORT:
		DeletePort(Write_Request->IOSer.io_Message.mn_ReplyPort);
	case ERR_OPEN_SER_WRITE:
		FreeMem(Write_Request,sizeof(*Write_Request));
	case ERR_ALLOC_WRITE_REQ:
		CloseDevice(Read_Request);
	case ERR_OPEN_SER_READ:
		DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort);
	case ERR_CRE_READ_PORT:
		FreeMem(Read_Request,sizeof(*Read_Request));
	case ERR_ALLOC_READ_REQ:
		CloseWindow( mywindow );
	case ERR_NEWWINDOW:
		CloseLibrary(GfxBase);
	case ERR_GFXBASE:
		CloseLibrary(IntuitionBase);
	case ERR_INTUITIONBASE:
		exit(error);
		break;
	}
	exit(error);
}

/*************************************************
*  Function to get a string from user.
*  ignores other events.
*************************************************/

filename(name)
char name[];
{
	int keepgoing = TRUE;
	int i = 0;

	while (keepgoing) {
		Wait(TYPED_CHAR);		/* ignore other events */
		GetMsg(consoleReadPort);	/* get character */
		switch (con_in[0]) {	/* Process it */
		case 13:	/* Carriage return */
		case 10:	/* Line feed */
			name[i] = '\0';
			emit(13);	
			keepgoing = FALSE;
			break;
		case 8:		/* Backspace */
		case 0177:	/* Delete */
			if (i > 0) {
				i--;
				emits("\b \b");
			}
			break;
		case 24:	/* ^X */
		case 033:	/* ESC */
			while ((i > 0) && i--)
				emits("\b \b");
			i = 0;
			break;
		default:
			name[i++] = con_in[0];
			emit(con_in[0]);
			break;
		}
		SendIO(consoleReadMsg);		/* requeue the read */
	} /* while KeepGoing */
	return (0);
}


/*****************************************************************
 *			Send ASCII file
 * Escape aborts send...
 *
 *****************************************************************/

Ascii_Send(file)
FILE *file;
{
	int c;

	while ((c=getc(trans)) != EOF) {
		/* check for serial or typed character */
		if (CheckIO(Read_Request))
			Handle_Modem();

		if (GetMsg(consoleReadPort)) {
			SendIO(consoleReadMsg);	/* requeue the read */
			if (con_in[0] == 033) {
				emits("File Send Cancelled\r\n");
				break;
			} /* if (con_in) */
		} /* if */
        	sendchar(c);
	} /* while */
	return (0);
}

/**************************************************************/
/* send char and read char functions for the xmodem function */
/************************************************************/

sendchar(ch)
int ch;
{
	ser_out[0] = ch;
	DoIO(Write_Request);
}

readchar()
{
	int rd, mask, ch;
	unsigned char c;

	rd = FALSE;

	while (rd == FALSE) {
		mask = Wait(SERIAL_CHAR | TYPED_CHAR);

		if (CheckIO(Read_Request) ) {
			WaitIO(Read_Request);
			ch = ser_in[0];
		        rd = TRUE;
		        SendIO(Read_Request);
	        }
		if (mask & TYPED_CHAR) {
			GetMsg(consoleReadPort);	/* get it	*/
			if (con_in[0] == 033) {
		               emits("\r\nUser Cancelled Transfer\r\n");
		               break; /* out of loop */
			}
			SendIO(consoleReadMsg);		/* requeue read */
		}

	} /* while */
	if (!rd) {
		timeout = TRUE;
		emits("\r\nTimeout Waiting For Character\r\n");
	}
	c = (char) ch;
	return ((int) c);
}

/**************************************/
/* xmodem send and recieve functions */
/************************************/

XMODEM_Read_File(file)
char *file;
{
    int firstchar, sectnum, sectcurr, sectcomp, errors, errorflag;
    unsigned int checksum, j, bufptr, i = 0;
    char numb[10];
    bytes_xferred = 0L;

    if ((fd = creat(file, 0)) < 0) {
        emits("Cannot Open File\r\n");
        return FALSE;
    } else
        emits("Receiving File\r\n");

    timeout = FALSE;
    sectnum = errors = bufptr = 0;
    sendchar(NAK);
    firstchar = 0;
    while (firstchar != EOT && errors != ERRORMAX) {
        errorflag = FALSE;
        do {                                   /* get sync char */
           firstchar = readchar();
           if (timeout == TRUE)
              return FALSE;
        } while (firstchar != SOH && firstchar != EOT);

	if  (firstchar == SOH) {
	    emits("Getting Block ");
	    sprintf(numb,"%4d",sectnum);
	    emits(numb);
	    emits("...");
	    sectcurr = readchar();
	    if (timeout == TRUE)
               return FALSE;
            sectcomp = readchar();
            if (timeout == TRUE)
               return FALSE;
            if ((sectcurr + sectcomp) == 255) {
                if (sectcurr == ((sectnum + 1) & 0xff)) {
                    checksum = 0;
                    for (j = bufptr; j < (bufptr + SECSIZ); j++) {
                        capbuf[j] = readchar();
                        if (timeout == TRUE)
                           return FALSE;
                        checksum = (checksum + capbuf[j]) & 0xff;
                        }
                    if (checksum == readchar()) {
                        errors = 0;
                        sectnum++;
                        bufptr += SECSIZ;
                        bytes_xferred += SECSIZ;
                        emits("verified\r\n");
                        if (bufptr == BufSize)
                            {
                            bufptr = 0;
                            if (write(fd, capbuf, BufSize) == EOF) {
                                emits("\r\nError Writing File\r\n");
                                return FALSE;
                                };
                            };
                        sendchar(ACK);
                        }
                    else
                        {
                        errorflag = TRUE;
                        if (timeout == TRUE)
                           return FALSE;
                        }
                    }
                else {
                    if (sectcurr == (sectnum & 0xff)) {
                        emits("\r\nReceived Duplicate Sector\r\n");
                        sendchar(ACK);
                        }
                    else
                        errorflag = TRUE;
                    }
                }
            else
                errorflag = TRUE;
            }
        if (errorflag == TRUE) {
            errors++;
            emits("\r\nError\r\n");
            sendchar(NAK);
            }
        };        /* end while */
            
    if ((firstchar == EOT) && (errors < ERRORMAX)) {
        sendchar(ACK);
        write(fd, capbuf, bufptr);
        close(fd);
        return TRUE;
        }
    return FALSE;
}

XMODEM_Send_File(file)
    char *file;
{
    int sectnum, bytes_to_send, size, attempts, c, i = 0;
    unsigned checksum, j, bufptr;
    char numb[10];

    timeout=FALSE;
    bytes_xferred = 0;
    if ((fd = open(file, 1)) < 0) {
        emits("Cannot Open Send File\r\n");
        return FALSE;
        }
    else
        emits("Sending File\r\n");
    attempts = 0;
    sectnum = 1;
    /* wait for sync char */
    j=1;
    while (((c = readchar()) != NAK) && (j++ < ERRORMAX));
    if (j >= (ERRORMAX))
        {
        emits("\r\nReceiver not sending NAKs\r\n");
        return FALSE;
        };

    while ((bytes_to_send = read(fd, capbuf, BufSize)) && attempts != RETRYMAX)
        {
        if (bytes_to_send == EOF) {
            emits("\r\nError Reading File\r\n");
            return FALSE;
            };

        bufptr = 0;
        while (bytes_to_send > 0 && attempts != RETRYMAX)
            {
            attempts = 0;
            do
                {
                sendchar(SOH);
                sendchar(sectnum);
                sendchar(~sectnum);
                checksum = 0;
                size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send;
                bytes_to_send -= size;
                for (j = bufptr; j < (bufptr + SECSIZ); j++)
                    if (j < (bufptr + size))
                        {
                        sendchar(capbuf[j]);
                        checksum += capbuf[j];
                        }
                    else
                        {
                        sendchar(0);
                        }
                sendchar(checksum & 0xff);
                attempts++;
                c = readchar();
                if (timeout == TRUE)
                   return FALSE;
                }
            while ((c != ACK) && (attempts != RETRYMAX));
            bufptr += size;
            bytes_xferred += size;
            emits("Block ");
            sprintf(numb,"%4d",sectnum);
            emits(numb);
            emits(" sent\r\n");
            sectnum++;
            }
        }
    close(fd);
    if (attempts == RETRYMAX) {
        emits("\r\nNo Acknowledgment Of Sector, Aborting\r\n");
        return FALSE;
    }
    else {
        attempts = 0;
        do {
            sendchar(EOT);
            attempts++;
        }
        while ((readchar() != ACK) &&
		(attempts != RETRYMAX) &&
		(timeout == FALSE));
        if (attempts == RETRYMAX)
            emits("\r\nNo Acknowledgment Of End Of File\r\n");
    };
    return TRUE;
}

/*************************************************
 * 		Utility functions
 ************************************************/


/*
 * function to output ascii chars to window
 */
emit(c)
char c;
{
	consoleWriteMsg->io_Length = 1;
	consoleWriteMsg->io_Data = (APTR) &c;
	DoIO(consoleWriteMsg);
}

/*
 * function to print a string
 */

emits(string)
char *string;
{
	consoleWriteMsg->io_Data = (APTR) string;
	consoleWriteMsg->io_Length = -1;
	DoIO(consoleWriteMsg);
}

/*****************************************************************/
/*    The following function initializes the structure arrays    */
/*   needed to provide the File menu topic.                      */
/*****************************************************************/

InitFileItems()
{
short n;

/* initialize each menu item and IntuiText with loop */
for( n=0; n<FILEMAX; n++ )
   {
   FileItem[n].NextItem = &FileItem[n]+1;
   FileItem[n].LeftEdge = 0;
   FileItem[n].TopEdge = 11 * n;
   FileItem[n].Width = 116;
   FileItem[n].Height = 11;
   FileItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP;
   FileItem[n].MutualExclude = 0;
   FileItem[n].ItemFill = (APTR)&FileText[n];
   FileItem[n].SelectFill = NULL;
   FileItem[n].Command = 0;
   FileItem[n].SubItem = NULL;
   FileItem[n].NextSelect = 0;

   FileText[n].FrontPen = 0;
   FileText[n].BackPen = 1;
   FileText[n].DrawMode = JAM2;     /* render in fore and background */
   FileText[n].LeftEdge = 0;
   FileText[n].TopEdge = 1;
   FileText[n].ITextFont = NULL;
   FileText[n].NextText = NULL;
   }
FileItem[FILEMAX-1].NextItem = NULL;

/* initialize text for specific menu items */
FileText[0].IText = (UBYTE *)"Ascii Capture";
FileText[1].IText = (UBYTE *)"Ascii Send";
FileText[2].IText = (UBYTE *)"Xmodem Receive";
FileText[3].IText = (UBYTE *)"Xmodem Send";
FileText[4].IText = (UBYTE *)"Quit";

return( 0 );
}

/*
 * Initialize the Settings main menu topic
 */
InitSetItems()
{
short n;

/* initialize each menu item and IntuiText with loop */
for( n=0; n<SETMAX; n++ )
   {
   SetItem[n].NextItem = &SetItem[n]+1;
   SetItem[n].LeftEdge = 0;
   SetItem[n].TopEdge = 11 * n;
   SetItem[n].Width = 76;
   SetItem[n].Height = 11;
   SetItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP;
   SetItem[n].MutualExclude = 0;
   SetItem[n].ItemFill = (APTR)&SetText[n];
   SetItem[n].SelectFill = NULL;
   SetItem[n].Command = 0;
   SetItem[n].NextSelect = 0;

   SetText[n].FrontPen = 0;
   SetText[n].BackPen = 1;
   SetText[n].DrawMode = JAM2;     /* render in fore and background */
   SetText[n].LeftEdge = 0;
   SetText[n].TopEdge = 1;
   SetText[n].ITextFont = NULL;
   SetText[n].NextText = NULL;
   }
SetItem[SETMAX-1].NextItem = NULL;

/* initialize text for specific menu items */
SetText[0].IText = (UBYTE *)"Baud Rate";
SetItem[0].SubItem = RSItem;

SetText[1].IText = (UBYTE *)"Parity";
SetItem[1].SubItem = PSItem;

SetText[2].IText = (UBYTE *)"Bits";
SetItem[2].SubItem = BSItem;
return( 0 );
}

/*****************************************************************/
/*    The following function initializes the structure arrays    */
/*   needed to provide the BaudRate menu topic.                  */
/*****************************************************************/

InitRSItems()
{
short n;

/* initialize each menu item and IntuiText with loop */
for( n=0; n<RSMAX; n++ )
   {
   RSItem[n].NextItem = &RSItem[n] + 1;
   RSItem[n].LeftEdge = 80;
   RSItem[n].TopEdge = 11 * n;
   RSItem[n].Width = 60;
   RSItem[n].Height = 11;
   RSItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT;
   RSItem[n].MutualExclude = (~(1 << n));
   RSItem[n].ItemFill = (APTR)&RSText[n];
   RSItem[n].SelectFill = NULL;
   RSItem[n].Command = 0;
   RSItem[n].SubItem = NULL;
   RSItem[n].NextSelect = 0;

   RSText[n].FrontPen = 0;
   RSText[n].BackPen = 1;
   RSText[n].DrawMode = JAM2;     /* render in fore and background */
   RSText[n].LeftEdge = 0;
   RSText[n].TopEdge = 1;
   RSText[n].ITextFont = NULL;
   RSText[n].NextText = NULL;
   RSText[n].IText = (UBYTE *) baudstrings[n];
   }
   RSItem[RSMAX-1].NextItem = NULL;
   RSItem[2].Flags |= CHECKED;	/* 1200 baud */
   return( 0 );
}


/*
 * Init Parity menu
 */
InitPSItems()
{
short n;

for( n=0; n<PSMAX; n++ )
   {
   PSItem[n].NextItem = &PSItem[n] + 1;
   PSItem[n].LeftEdge = 80;
   PSItem[n].TopEdge = 11 * n;
   PSItem[n].Width = 60;
   PSItem[n].Height = 11;
   PSItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT;
   PSItem[n].MutualExclude = (~(1 << n));
   PSItem[n].ItemFill = (APTR)&PSText[n];
   PSItem[n].SelectFill = NULL;
   PSItem[n].Command = 0;
   PSItem[n].SubItem = NULL;
   PSItem[n].NextSelect = 0;

   PSText[n].FrontPen = 0;
   PSText[n].BackPen = 1;
   PSText[n].DrawMode = JAM2;     /* render in fore and background */
   PSText[n].LeftEdge = 0;
   PSText[n].TopEdge = 1;
   PSText[n].ITextFont = NULL;
   PSText[n].NextText = NULL;
   }

   PSItem[PSMAX-1].NextItem = NULL;
   PSItem[0].Flags |= CHECKED;	/* no parity to start with */

   PSText[0].IText = (UBYTE *) "   None";
   PSText[1].IText = (UBYTE *) "   Even";
   PSText[2].IText = (UBYTE *) "   Odd";
   return( 0 );
}

/*
 * Init byte length menu
 */

InitBSItems()
{
short n;

for( n=0; n<BSMAX; n++ )
   {
   BSItem[n].NextItem = &BSItem[n] + 1;
   BSItem[n].LeftEdge = 80;
   BSItem[n].TopEdge = 11 * n;
   BSItem[n].Width = 50;
   BSItem[n].Height = 11;
   BSItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT;
   BSItem[n].MutualExclude = (~(1 << n));
   BSItem[n].ItemFill = (APTR)&BSText[n];
   BSItem[n].SelectFill = NULL;
   BSItem[n].Command = 0;
   BSItem[n].SubItem = NULL;
   BSItem[n].NextSelect = 0;

   BSText[n].FrontPen = 0;
   BSText[n].BackPen = 1;
   BSText[n].DrawMode = JAM2;     /* render in fore and background */
   BSText[n].LeftEdge = 0;
   BSText[n].TopEdge = 1;
   BSText[n].ITextFont = NULL;
   BSText[n].NextText = NULL;
   }

   BSItem[BSMAX-1].NextItem = NULL;
   BSItem[1].Flags |= CHECKED;	/* 8 bit bytes */

   BSText[0].IText = (UBYTE *) "   7";
   BSText[1].IText = (UBYTE *) "   8";
   return( 0 );
}

/*****************************************************************/
/*    The following function initializes the structure arrays    */
/*   needed to provide the Tweak menu topic.                     */
/*****************************************************************/

InitTweakItems()
{
short n;

/* initialize each menu item and IntuiText with loop */
for( n=0; n < TWMAX; n++ )
   {
   TWItem[n].NextItem = &TWItem[n]+1;
   TWItem[n].LeftEdge = 0;
   TWItem[n].TopEdge = 11 * n;
   TWItem[n].Width = 116;
   TWItem[n].Height = 11;
   TWItem[n].Flags = ITEMTEXT | ITEMENABLED | CHECKIT | HIGHCOMP;
   TWItem[n].MutualExclude = 0;
   TWItem[n].ItemFill = (APTR) &TWText[n];
   TWItem[n].SelectFill = NULL;
   TWItem[n].Command = 0;
   TWItem[n].SubItem = NULL;
   TWItem[n].NextSelect = 0;

   TWText[n].FrontPen = 0;
   TWText[n].BackPen = 1;
   TWText[n].DrawMode = JAM2;     /* render in fore and background */
   TWText[n].LeftEdge = 0;
   TWText[n].TopEdge = 1;
   TWText[n].ITextFont = NULL;
   TWText[n].NextText = NULL;
   }
   TWItem[TWMAX-1].NextItem = NULL;

   /* Item 0 -- BS -> DEL */
   TWText[0].IText = (UBYTE *) "   BS <-> DEL";
   if (bs_to_del)
	   TWItem[0].Flags |= CHECKED;

   /* Item 1 -- local echo */
   TWText[1].IText = (UBYTE *) "   Local Echo";
   if (echo)
	   TWItem[1].Flags |= CHECKED;

   /* Item 2 -- auto wrap */
   TWText[2].IText = (UBYTE *) "   Auto Wrap";
   if (wrap)
	   TWItem[2].Flags |= CHECKED;

   /* Item 3 -- new line -> carriage return + newline */
   TWText[3].IText = (UBYTE *) "   Newline";
   if (newline)
	   TWItem[3].Flags |= CHECKED;

   /* item 4 -- show throughput (debug) */
   TWText[4].IText = (UBYTE *) "   Throughput";
   if (debug)
	   TWItem[4].Flags |= CHECKED;

   return( 0 );
}

/**********************************************************************/
/*   The following function initializes the Menu structure array with */
/*  appropriate values for our simple menu strip.  Review the manual  */
/*  if you need to know what each value means.                        */
/**********************************************************************/
InitMenu()
{
	/* File menu */
	menu[0].NextMenu = &menu[1];
	menu[0].LeftEdge = 5;
	menu[0].TopEdge = 0;
	menu[0].Width = 50;
	menu[0].Height = 10;
	menu[0].Flags = MENUENABLED;
	menu[0].MenuName = "File";
	menu[0].FirstItem = &FileItem[0];

	/* Settings menu */
	menu[1].NextMenu = &menu[2];
	menu[1].LeftEdge = 2 + menu[0].Width + menu[0].LeftEdge;
	menu[1].TopEdge = 0;
	menu[1].Width = 76;
	menu[1].Height = 10;
	menu[1].Flags = MENUENABLED;
	menu[1].MenuName = "Settings";
	menu[1].FirstItem = &SetItem[0];

	/* Tweak menu */
	menu[2].NextMenu = NULL;
	menu[2].LeftEdge = 2 + menu[1].Width + menu[1].LeftEdge;
	menu[2].TopEdge = 0;
	menu[2].Width = 60;
	menu[2].Height = 10;
	menu[2].Flags = MENUENABLED;
	menu[2].MenuName = "Prefs";
	menu[2].FirstItem = &TWItem[0];

	return( 0 );
}

/*
 * Open up a console device for writing only
 */

OpenConsoleW(writerequest,readrequest,window)
struct IOStdReq *writerequest, *readrequest;
struct Window *window;
{
	int error;

	writerequest->io_Data = (APTR) window;
	writerequest->io_Length = sizeof(*window);
	error = OpenDevice("console.device",0,writerequest,0);
	readrequest->io_Device = writerequest->io_Device;
	readrequest->io_Unit = writerequest->io_Unit;
	return (error);
}