[comp.sys.atari.st] GFA Basic

logajan@ns.UUCP (John Logajan x3118) (01/10/89)

I just sent my GFA Basic (2.0) implementation of uucp/uucico to the
comp.sources.atari.st moderator.  This is a human readable listing
of a uucp compatible file transfer program (the thing that dialup
sites use for Usenet mail and news transfer, like what you are reading
now.)  I also included a write-mail and a read-mail program, along with
some setup information and a discussion of the protocol, for those who
seek to improve upon it.  Collectively they are released into the
public domain and are known as MailTruk V1.0.

I have been using them for the last week (not a lot of debug time) after
writing them for a month or two.  I increased my "effort" after my
Telebit TrailBlazer Plus arrived in mid december.  Now my TB+ can run
at nearly theoretical full speed.  I did a 100,000 byte transfer at an
average rate of 1400 cps!  (This is in compiled mode, in interpreter mode
the rate was about 1200 cps.)  (Those stupid one-packet-window uucp hacks
make 2400 baud run at an effective 1200 baud rate, or ten times slower
that the TB+ with 3-packet-windows!!!)

For those of you who like to experiment, you can change the packet/window
size to any of the allowed values, w=1-7 and p=32-4096.

I wrote it just for me, but I hope someone else can find a use for it too.

-- 
- John M. Logajan @ Network Systems; 7600 Boone Ave; Brooklyn Park, MN 55428  -
- ...rutgers!umn-cs!ns!logajan / logajan@ns.network.com / john@logajan.mn.org -

covertr@gtephx.UUCP (Richard E. Covert) (01/17/89)

I am interested in any software that would allow me to link my 520ST (one
meg RAM, 20 meg disk) to my uucp node at work. I have permission from the
uucp admin at work to do this. Could someone tell me how I can get a disk
of software?? I would be willing to call long distance to get it. I can call
upto 9600 baud using a US Robotics modem. If anyone out there can help me please
leave me e-mail ASAP.

TIA

Richard (Forem sysop) Covert

logajan@ns.UUCP (John Logajan x3118) (01/20/89)

I am posting this here because I have had a few requests for it ASAP.

Below are five files generically named MailTruk Release V1.0.
MailTruk is a GFA Basic (2.0) implementation of uucp/uucico.
MailTruk is intended to allow non-unix/non-C Atari ST's email
access to the Usenet community.  The five files included below,
between *****'s are, in order: MAILTRUK.DOC,  MAILTRUK.LST,
WRITMAIL.LST, READMAIL.LST, and PROTOCOL.DOC.  Thanks -- John Logajan.

************************************************************************

                      MailTruk Documentation
                                by
                    John Logajan, January 1989
                         4248 Hamline Ave
                      Arden Hills, MN  55112
                       john@logajan.mn.org


INTRODUCTION TO THE NETWORK

Welcome to the world of uucp style data exchange.  Uucp stands for 
Unix to Unix copy.  Unix is an operating system used by a large 
number of computers.  A large network of computers running uucp 
compatible data exchange has evolved over the last several years.  
This network encompasses university, corporate, governmental, and 
individually owned computers.  It is estimated that there are over 
10,000 computers on the net, with approximately 400,000 users.  
The two primary functions of the net are private electronic mail 
and "broadly cast" electronic news transfer.  The Usenet News 
consists of some 350 subject categories into which several 
thousand articles a day are posted by users.  An average day's 
news is typically four million characters -- and growing.  Anyone 
receiving a full newsfeed is more and more feeling the need for 
faster data communications links, since such volume at 2400 baud 
requires five hours if uncompressed or 2.5 hours if compressed. 


INTRODUCTION TO THE MAILTRUK, READMAIL, AND WRITMAIL PROGRAMS

MailTruk, ReadMail, and WritMail are uucp compatible 
communications programs that run on Atari ST computers.   The 
programs are written in GFA Basic (2.0) and are freely distributed 
as a readable listings in the public domain.  Files included in 
the distribution include:
MAILTRUK.LST, READMAIL.LST, WRITMAIL.LST, MAILTRUK.DOC, 
PROTOCOL.DOC

WritMail is used to write your outgoing mail.  Writmail's main 
task is to format your message so that other computers on the net 
recognize what you have sent and where it is going.  Each, in 
turn, passes it along until it hopefully reaches your intended 
recipient.

MailTruk is the actual communications program.  It first dials 
your neighbor site, establishes protocol agreement, and then sends 
the messages, if any, that you have previously prepared with 
WritMail.  When MailTruk has finished sending, it requests to 
receive any mail that the remote site has pending for you.  After 
it receives all incoming mail, MailTruk terminates the connection.

ReadMail allows you to read your mail in a convenient manner.  The 
main objection to reading you mail files directly with GEM 
commands is that Unix machines use linefeed characters as end-of-
line indicators rather than the carriage return character used by 
GEM.  Thus, direct reading of mail files results in a confusing 
presentation.

Although MailTruk can transfer the file types used to send the 
Network News, additional file pre- and post-processing is required 
to read or write News articles.  ReadMail and WritMail DO NOT 
handle the News format.  Uncompressed News would be a fairly 
straight forward task to handle, but compressed and batched News 
will require additional sophistication.  Let me know if you feel 
motivated to write such a program!


SETTING EVERYTHING UP

First -- You need a site to call, account information for that 
site, and a modem.  Since this program is being distributed over 
the net, if you track back from where this program came from, 
you're bound to run into somebody who knows your local net 
arrangement.  (I pay $25 a year to a guy who runs a "domain park" 
for my access.  He, in turn, calls other bigger sites -- and so 
on.)

Second -- All mail going to a particular site is placed in its own 
directory.  All mail coming to your site is placed in its own 
directory.  You should create these directories before running the 
programs.  I am site -logajan-, I call one site -bungia-.  So, I 
created a directory called MAIL on my C: drive where I put all my 
programs, and I created two sub-directories, BUNGIA and LOGAJAN, 
i.e. C:\MAIL\BUNGIA\
     C:\MAIL\LOGAJAN\

Third -- All three programs are totally self-contained in that 
they do not share an external common configuration file.  So you 
will have to insure that each of the important variables, 
including the directory names mentioned above, in each of the 
programs is correct and consistent.  The variables are grouped 
near the beginning of each program.  You WILL have to customize 
these variables for these programs to work!

Fourth -- If you have multiple sites to call, you will have to 
make multiple versions of the MailTruk program (or modify it to 
handle multiple cases.)  You will also want to write a program 
that recognizes messages which are just passing through, and 
"rewrites" the pertinent addresses, and places them back out in 
the outbound message area.

Fifth -- Otherwise you are a "leaf" site (you only call one 
machine) and any mail with your machine name in it is assumed to 
be to you, no matter what user name or additional path is in the 
To: address line.

Sixth -- Paths; the From: and To: portion of messages; are a 
somewhat mysterious subject.  Basically you have to know, at a 
minimum, the recipient's user-name and machine-name, and the path 
to the nearest smart mailer site.   Otherwise you can specify the 
entire path -- but some smart sites end up sending it the route 
they think is best anyhow.

  If I want to send to jack at atari, I enter the path as:
     bungia!atari!jack     Note:  nearest!next!next!farthest!user
     (my neighbor, bungia, knows the tortuous route to atari)

  or bungia!umn-cs!rutgers!att.att.com!wally if I want to get to
     wally at att and know the complete path.

You will often see @'s and %'s in paths.  Basically you just read 
these in the other direction, i.e.:

     john@logajan.mn.org@bungia@shamash@nic.mr.net   is an actual
     path TO my machine from nic.mr.net.

However, note that WritMail forces you to state the path with at 
least one (!) symbol.  Your neighbor's machine is always the first 
name in the path, therefore you could do:

     bungia!ben@franklin.electric.com


Seventh -- Hopefully there is enough information in the listings 
for you to set up your own site and get it operational.
                           Good luck.

**********************************************************************

Rem  MAILTRUK V1.0 -- GFA Basic 2.0 / Atari ST implementation of uucp/uucico.
Rem                      --- PUBLIC DOMAIN ---
Rem  This program dials up computer sites running Unix or Unix clone uucp,
Rem      allowing the transfer of e-mail, news and other data files.
Rem
Rem       Totally original code by:  John Logajan, January 1989.
Rem                                  4248 Hamline Ave
Rem                                  Arden Hills, MN 55112
Rem      (john@logajan.mn.org  or  ...rutgers!bungia!logajan!john)
Rem
Rem    The next eight lines must be customized for each user/site.
Rem
Mysite$="logajan"              ! Your site machine name.  (You choose!)
Myuser$="logajan"              ! Your user/account name for remote site.
Mypw$="youguess"               ! Your password for remote site.
Sitedir$="\mail\bungia"        ! Directory of files to send only to that site.
Sitercv$="\mail\"+Mysite$      ! Directory for all incoming files.
Siteph$="123-4567"             ! Remote site telephone number.
Retry!=True                    ! Should we retry dialing if busy/no answer.
Void Xbios(15,4,0,&H88,1,1,-1) ! RS232 configuration/baud rate. (See below.)
Rem
Rem Configure RS232 - Xbios(15,baud,flow,ctrl,rst,xst,scr).
Rem baud = 0/19200, 1/9600, 4/2400, 7/1200, 9/300.
Rem flow = 0/None. (UUCP forbids xoff/xon! ST's RTS/CTS works goofy!)
Rem ctrl = 8bits, 1stop, noparity.
Rem rst = recv enabled.
Rem xst = xmit enabled.
Rem scr = not used.
Rem
Rwinsiz%=3           ! Number of packets in receive window. (Standard=3)
Rpktsiz%=64          ! Number of bytes in a receive packet. (Standard=64)
Rem
Rem Assembler code for calculating the checksum (speedy.)  Does the check-
Rem sum calculation on a packetsize worth of data starting at Buffer.
Rem The control byte is also included in the sum and everthing is sub-
Rem tracted from AAAA hex.
Rem            Checksum=C:Chk%(L:buffer,W:packetsize,W:controlbyte)
Rem
Data "206F0004322F0008342F000A203C0000FFFF4243E358280042851A18D0453A00B345"
Data "D645B0846E02B7400441000166E40242FFFFB142303CAAAA904202800000FFFF4E75"
Read A$
Read B$
A$=A$+B$
Chk$=""
For J%=1 To Len(A$) Step 2
  Chk$=Chk$+Chr$(Val("&H"+Mid$(A$,J%,2)))
Next J%
Chk%=Varptr(Chk$)
Rem
Rem Assembler code for RS232 block input (speedy.)  Puts x chars into a
Rem buffer, or times out after 12 seconds.
Rem            Remainder=C:Rcv%(L:buffer,W:byteswanted)
Rem
Data "286F0004382F000842A73F3C00204E415C8F2E002A39000004BA068500000960"
Data "3F3C00013F3C00014E4D588F4A4067143F3C00013F3C00024E4D588F18C05344"
Data "670C60DC2C39000004BA9C856DD22F073F3C00204E415C8F20044E75"
Read A$
Read B$
A$=A$+B$
Read B$
A$=A$+B$
Rcv$=""
For J%=1 To Len(A$) Step 2
  Rcv$=Rcv$+Chr$(Val("&H"+Mid$(A$,J%,2)))
Next J%
Rcv%=Varptr(Rcv$)
Dim Rcxx%(Rpktsiz%/4+2)             ! Build an internal input buffer.
Rcvbf%=Varptr(Rcxx%(0))
Dim Wfil$(2)
Wfm=0
Wfp%=Varptr(Wfm)                    ! Build a frame buffer.
Rs232p%=Xbios(14,0)                 ! Get RS232 TOS buffer info pointer.
Rinsiz%=((Rpktsiz%+6)*Rwinsiz%+128)
Dim Rin%(Rinsiz%/4+1)               ! Make a large RS232 TOS input buffer.
Lpoke Rs232p%,Varptr(Rin%(0))
Dpoke Rs232p%+4,Rinsiz%
Dpoke Rs232p%+6,0                   ! Flag it empty.
Dpoke Rs232p%+8,0
Open "",#2,"AUX:"                   ! Open RS232 port as file #2.
Rem
Rem   You will probably need to customize the dialing part of the program,
Rem   depending upon the quirks of the site you are trying to call, and
Rem   your modem response codes.
Rem
Print "Dialing.    Push SPACE key to abort connection attempt."
Repeat
  @Ostr("ATDT"+Siteph$+"\0D")         !  Dial remote site.
  @Waitfor("CONNECT",60)
  Exit If Not Retry!
  If Not Found!
    Print "Busy/no answer. Dialing again."
  Endif
Until Found!
Print "Connected."
Retry!=False
Pause 200
Out 1,&HD                            ! Send a couple of CR's to prime remote.
Pause 50
Out 1,&HD
Pause 50
Out 1,&HD
Pause 50
Out 1,&HD
@Waitfor("ogin:",30)
Pause 50
@Ostr(Myuser$+"\0D")
@Waitfor("sword:",30)
@Ostr(Mypw$+"\0D")
@Waitfor("Shere",30)
Print "Logged in."
Rem
Rem Initialization sequence.
Rem
@Ostr("\10S"+Mysite$+"\0A")
@Waitfor("ROK",30)
@Waitfor("P",30)
@Waitfor("g",5)
@Ostr("\10Ug\0A")
Inita!=False
Initb!=False
Initc!=False
For Wf%=1 To 10                 ! INIT with window size / data segement size.
  If Inita!=False Or Initb!=False
    Wcc%=&H38 Or Rwinsiz%
    @Wctlpkt(2)                      ! inita window size.
  Endif
  @Waitframe
  If Found! And (Cntrol% And &HF8)=&H38
    Inita!=True
    Xwinsiz%=Cntrol% And 7
    Rpktcod%=Int(Log(Rpktsiz%)/Log(2)-4.9)
    Wcc%=&H30 Or Rpktcod%
    @Wctlpkt(2)                      ! initb packet size.
    @Waitframe
  Endif
  If Found! And (Cntrol% And &HF8)=&H30
    Initb!=True
    Xpktcod%=(Cntrol% And 7)+1
    Xpktsiz%=32*2^(Xpktcod%-1)
    Xpktsizh%=Xpktsiz%+6
  Endif
  Exit If Inita! And Initb!
Next Wf%
If Initb!
  Wcc%=&H28 Or Rwinsiz%
  @Wctlpkt(2)                        ! initc window size.
  For Wf%=1 To 3
    @Waitframe
    If Found! And (Cntrol% And &HF8)=&H28
      Initc!=True
    Endif
    Exit If Initc!
  Next Wf%
Endif
If Inita!=False Or Initb!=False Or Initc!=False
  Print "Failed initilization."
  @Hangup
Endif
Print "They want a sending window size = ";Xwinsiz%
Print "They want a sending data packet size = ";Xpktsiz%
Dim Xbuf%(2*Xpktsizh%)              ! Build an outgoing data buffer.
Xppt%=Varptr(Xbuf%(0))
Rseq%=0
Rrseq%=0
Xseq%=0
Xack%=0
Rem
Rem Since we called, we are master and send our stuff first.
Rem
Sitewrk$=Sitedir$+"\WORK"           ! Temporary work-list file.
Sitecfl$=Sitedir$+"\*.C"
If Exist(Sitewrk$)
  Kill Sitewrk$                     ! Get rid of old stale one.
Endif
If Exist(Sitecfl$)                  ! Do we have anything to send???
  Dir Sitecfl$ To Sitewrk$          ! Then make a list of those files.
  Open "I",#3,Sitewrk$
  While Not Eof(#3)                 ! Setup to send those files, pair by pair.
    Line Input #3,Sfil$
    Sfil$=Sitedir$+"\"+Left$(Sfil$,Instr(Sfil$,"."))
    Cfil$=Sfil$+"C"
    Wfil$(1)=Sfil$+"D"
    Wfil$(2)=Sfil$+"X"
    If Exist(Cfil$)
      Open "I",#4,Cfil$
      For Wrks%=1 To 2
        Line Input #4,Wrklin$       ! Get D. or X. worklines out of C.
        Wrklin$=Wrklin$+Chr$(0)
        If Exist(Wfil$(Wrks%))
          Print "SEND:"'Wrklin$
          Xfdone!=False
          Xrqp%=0
          While Not Xfdone!         ! Send the workline.
            @Wrqtpkt
          Wend
          @Waitdata
          If Peek(Rcvbf%)<>Asc("S")
            Print "Send request failed."
            @Hangup
          Endif
          If Peek(Rcvbf%+1)=Asc("Y")
            Open "I",#1,Wfil$(Wrks%)
            Xfl%=Lof(#1)
            Xfp%=0
            Xfdone!=False
            While Not Xfdone!        ! Send D. or X. file.
              @Wfilepkt
            Wend
            @Waitdata
            If Peek(Rcvbf%)<>Asc("C") Or Peek(Rcvbf%+1)<>Asc("Y")
              Print "Send failed."
              @Hangup
            Endif
            Close #1
          Else                       ! They won't let us do something.
            Print "Send request refused by remote site."
          Endif
          Kill Wfil$(Wrks%)
        Endif
      Next Wrks%
      Close #4
      Kill Cfil$
    Endif
  Wend
  Close #3
  Kill Sitewrk$
Endif
Rem
Rem We are done sending, now we become slave to receive.
Rem
Wrklin$="H"+Chr$(0)
Xrqp%=0
@Wrqtpkt
@Waitdata
If Peek(Rcvbf%)=Asc("H")
  If Peek(Rcvbf%+1)=Asc("N")             ! HN means they have mail for us.
    Do
      Rwfr!=False
      Wrklin$=""
      While Not Rwfr!
        @Waitdata                        ! Get their workline request.
        For Wf%=0 To Rpktsiz%-1
          Wlv%=Peek(Rcvbf%+Wf%)
          If Wlv%=0
            Rwfr!=True
          Else
            Wrklin$=Wrklin$+Chr$(Wlv%)
          Endif
          Exit If Rwfr!
        Next Wf%
      Wend
      Rwff$=Left$(Wrklin$,1)
      Exit If Rwff$="H"                  ! If H then they are done too.
      Print "RCV:"'Wrklin$
      If Rwff$="S"
        Wlst%=Instr(5,Wrklin$," ")
        Rwff$=Mid$(Wrklin$,Wlst%+1,1)    ! We have to shorten the file name.
        Rfil$=Rwff$+Mid$(Wrklin$,Instr(Wlst%,Wrklin$," ")-4,4)+"."+Rwff$
        Open "O",#1,Sitercv$+"\"+Rfil$
        Wrklin$="SY"+Chr$(0)             ! Tell them it's okay to send.
        Xrqp%=0
        @Wrqtpkt
        Rdone!=False
        While Not Rdone!                 ! Get D. or X. file contents.
          @Waitdata
          If Ptyp%=&H80
            Bput #1,Rcvbf%,Rpktsiz%
          Else
            Dif%=Peek(Rcvbf%)
            Dfc%=1
            If Dif%=>128
              Dif%=Dif%-128+Peek(Rcvbf%+1)*128
              Dfc%=2
            Endif
            Dif%=Rpktsiz%-Dif%
            If Dif%<>0
              Bput #1,Rcvbf%+Dfc%,Dif%
            Else
              Rdone!=True
            Endif
          Endif
        Wend
        Close #1
        Wrklin$="CY"+Chr$(0)             ! Acknowledge successful copy.
        Xrqp%=0
        @Wrqtpkt
      Else
        Print "Illegal request from remote site:"
        Print Wrklin$
        Wrklin$=Rwff$+"N"+Chr$(0)        ! Tell them sorry, but no.
        Xrqp%=0
        @Wrqtpkt
      Endif
    Loop
    Wrklin$="HY"+Chr$(0)
    Xrqp%=0
    @Wrqtpkt
    @Waitdata
    If Peek(Rcvbf%)<>Asc("H") Or Peek(Rcvbf%+1)<>Asc("Y")
      Print "Failed looking to hangup."
      @Hangup
    Endif
    @Fini
  Else
    Wrklin$="HY"+Chr$(0)
    Xrqp%=0
    @Wrqtpkt
    @Fini
  Endif
Else
  Print "Mode switching failed."
  @Hangup
Endif
End
Procedure Fini
  Print "Done. Terminating session."
  @Ostr("\10\09\A2\AA\08\09")
  @Waitframe
  If Frmcmd%<>8
    Print "Failed waiting for CLOSE!"
    @Hangup
  Endif
  @Ostr("\10OOOOOO\0A")
  @Waitfor("OOO",5)
  @Ostr("\10OOOOOO\0A")
  Print "Conversation complete."
  @Hangup
Return
Procedure Ostr(O$) ! Send ASCII or HEX \XX (2 nybbles - uppercase.)
  L%=Len(O$)
  J%=0
  Repeat
    Inc J%
    C%=Asc(Mid$(O$,J%,1))
    If C%=&H5C
      Inc J%
      C%=Val("&H"+Mid$(O$,J%,2))
      Inc J%
    Endif
    Out 1,C%
  Until J%=L%
Return
Procedure Waitfor(O$,Tx%) ! Look for O$ in input stream for Tx seconds.
  Pkey!=False             ! Pressing space key aborts during dial up part.
  Found!=False
  Ol%=Len(O$)
  Cp%=1
  T%=Timer+Tx%*200
  While Timer<T%
    If Inp?(1)
      C%=Inp(1) And &H7F
      If Asc(Mid$(O$,Cp%,1))=C%
        If Cp%=Ol%
          Found!=True
        Endif
        Inc Cp%
      Else
        If Cp%<>1
          Cp%=1
          If Asc(Mid$(O$,Cp%,1))=C%
            Inc Cp%
          Endif
        Endif
      Endif
    Endif
    Exit If Found!
    If Inp?(2)
      If Inp(2)=Asc(" ")      ! Abort during login if SPACE key is pressed.
        Pkey!=True
      Endif
    Endif
    Exit If Pkey!
  Wend
  If ((Not Found!) And Not Retry!) Or Pkey!
    Print "Failed waiting for: ";O$
    @Hangup
  Endif
Return
Procedure Waitframe                 ! Wait for a six byte framing envelope.
  Found!=False
  Rr!=False
  Dpkt!=False
  Wfr%=C:Rcv%(L:Wfp%,6)
  Repeat
    Cntrol%=Peek(Wfp%+4)
    Rsum1%=Peek(Wfp%+2)
    Rsum2%=Peek(Wfp%+3)
    Xs%=Peek(Wfp%+1) Xor Rsum1% Xor Rsum2% Xor Cntrol%
    If Wfr%=0 And Peek(Wfp%)=&H10 And Xs%=Peek(Wfp%+5)
      Found!=True
      Ptyp%=Cntrol% And &HC0
      If Ptyp%=0
        Xack%=Cntrol% And 7
        Frmcmd%=Cntrol% And &H38
        If Frmcmd%=&H20
          Rr!=True
        Endif
      Else
        Dpkt!=True
        Rrseq%=(Cntrol%/8) And 7
        Rsum%=Rsum2%*256+Rsum1%
      Endif
    Else
      If Wfr%=0
        Bmove Wfp%+1,Wfp%,5
        Wfr%=C:Rcv%(L:Wfp%+5,1)
      Endif
    Endif
    Exit If Found!
  Until Wfr%<>0
Return
Procedure Hangup               ! Hangup.
  Print "Hanging Up!"
  @Ostr("\0D")
  Pause 60
  @Ostr("+++")
  Pause 60
  @Ostr("\0DATH\0D")
  Pause 25
  Void Xbios(30,&H10)          ! Drop DTR for 1/2 second.
  Pause 25
  Void Xbios(29,&HEF)          ! Raise DTR.
  End
Return
Rem
Rem Writes:  One data packet, from file opened as #1, to RS232 opened as #2.
Rem Returns: Xfdone!=True after last packet sent.
Rem Initial: Xfl%=Lof(#1), Xfp%=0, Xppt%=base packet pointer,
Rem          xpktsiz%, xpktcod%, xpktsizh%.
Rem Current: Rseq%=last rcvd packet sequence number, Xseq%=last xmited.
Rem Updates: Xseq%=xmited packet sequence number, Xfp%=xmited data pointer.
Rem
Procedure Wfilepkt
  Xfpo%=Xfp%
  Xfp%=Xfp%+Xpktsiz%
  Xseq%=(Xseq%+1) And 7
  Xph%=Xppt%+Xseq%*Xpktsizh%
  Xpd%=Xph%+6
  Poke Xph%,&H10
  Poke Xph%+1,Xpktcod%
  If Xfp%<=Xfl%
    Bget #1,Xpd%,Xpktsiz%             ! Full Packet.
    Xctrl%=&H80 Or Xseq%*8 Or Rseq%
    Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%)
    Poke Xph%+2,Xsum%
    Xf1%=Xsum%/256
    Poke Xph%+3,Xf1%
    Poke Xph%+4,Xctrl%
    Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%)
    @Wchkwin(0)
  Else
    If Xfpo%<Xfl%
      Xbun%=Xpktsiz%-(Xfl%-Xfpo%)     ! Short Packet. (If needed.)
      If Xbun%<128
        Poke Xpd%,Xbun%
        Bget #1,Xpd%+1,Xfl%-Xfpo%
      Else
        Poke Xpd%,Xbun% And &H7F Or &H80
        Poke Xpd%+1,Xbun%/128
        Bget #1,Xpd%+2,Xfl%-Xfpo%
      Endif
      Xctrl%=&HC0 Or Xseq%*8 Or Rseq%
      Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%)
      Poke Xph%+2,Xsum%
      Xf1%=Xsum%/256
      Poke Xph%+3,Xf1%
      Poke Xph%+4,Xctrl%
      Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%)
      @Wchkwin(0)
    Else
      If Xpktsiz%<128                 ! Empty Packet. (Always sent last.)
        Poke Xpd%,Xpktsiz%
      Else
        Poke Xpd%,Xpktsiz% And &H7F Or &H80
        Poke Xpd%+1,Xpktsiz%/128
      Endif
      Xctrl%=&HC0 Or Xseq%*8 Or Rseq%
      Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%)
      Poke Xph%+2,Xsum%
      Xf1%=Xsum%/256
      Poke Xph%+3,Xf1%
      Poke Xph%+4,Xctrl%
      Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%)
      @Wchkwin(1)
      Xfdone!=True
    Endif
  Endif
Return
Rem
Rem This procedure sends data packets used for H,S,C type signals.
Rem It differs from the other data packets in that there are no short
Rem packets.  Instead a zero follows each command string and a zero
Rem must appear as the last byte in the packet.
Rem
Procedure Wrqtpkt             ! Initial: Xrqp%=0, Wrklin$, Xfdone!=False.
  Xstp%=Varptr(Wrklin$)
  Xstl%=Len(Wrklin$)
  Xrqpo%=Xrqp%
  Xrqp%=Xrqp%+Xpktsiz%
  Xseq%=(Xseq%+1) And 7
  Xph%=Xppt%+Xseq%*Xpktsizh%
  Xpd%=Xph%+6
  Poke Xph%,&H10
  Poke Xph%+1,Xpktcod%
  Bmove Xstp%+Xrqpo%,Xpd%,Xpktsiz%
  If Xrqp%>Xstl%
    Poke Xpd%+Xpktsiz%-1,0
    Xfdone!=True
  Endif
  Xctrl%=&H80 Or Xseq%*8 Or Rseq%
  Xsum%=C:Chk%(L:Xpd%,W:Xpktsiz%,W:Xctrl%)
  Poke Xph%+2,Xsum%
  Xf1%=Xsum%/256
  Poke Xph%+3,Xf1%
  Poke Xph%+4,Xctrl%
  Poke Xph%+5,(Xpktcod% Xor Xsum% Xor Xf1% Xor Xctrl%)
  @Wchkwin(1)
Return
Rem
Rem This procedure sends RR's, RJ's, CLOSE, and INITA,B,C's.
Rem
Procedure Wctlpkt(Wct%)       ! wct%=0 for RR, 1 for Rj, 2 for other.
  If Wct%=0
    Wcc%=&H20 Or Rseq%
  Else
    If Wct%=1
      Wcc%=&H10 Or Rseq%
    Endif
  Endif
  Wc1%=&HAAAA-Wcc%
  Wc0%=Wc1% And &HFF
  Div Wc1%,256
  Wcx%=9 Xor Wc0% Xor Wc1% Xor Wcc%
  Out 1,&H10
  Out 1,&H9
  Out 1,Wc0%
  Out 1,Wc1%
  Out 1,Wcc%
  Out 1,Wcx%
Return
Rem
Rem This procedure waits to receive a data packet.  It RR's them as soon
Rem as it sees them.
Rem
Procedure Waitdata
  For Wf%=1 To 10
    @Waitframe
    If Dpkt!
      Nwp%=C:Rcv%(L:Rcvbf%,Rpktsiz%)
      Csum%=C:Chk%(L:Rcvbf%,Rpktsiz%,Cntrol%)
      If Rsum%=Csum% And ((Rseq%+1) And 7)=Rrseq%  ! Verify data and seq.
        Rseq%=Rrseq%
        @Wctlpkt(0)
      Else
        Found!=False
      Endif
    Else
      Found!=False
    Endif
    Exit If Found!
    If Not Rr!                     ! Gets around a Telebit peculiarity.
      @Wctlpkt(1)
    Endif
  Next Wf%
  If Not Found!
    Print "Failed waiting for a data frame."
    @Hangup
  Endif
Return
Rem
Rem This procedure handles the windowing of sent data packets.
Rem It sends as many packets as allowed before waiting for RR's.
Rem
Procedure Wchkwin(Flush%)
  If ((Xack%+Xwinsiz%+1) And 7)<>Xseq%
    Bput #2,Xph%,Xpktsizh%
  Else
    For Wf%=1 To 10
      @Waitframe
      If Rr!
        Bput #2,Xph%,Xpktsizh%
      Else
        Found!=False
        For Jr%=1 To Xwinsiz%
          Xjr%=(Xack%+Jr%) And 7
          Bput #2,Xppt%+Xjr%*Xpktsizh%,Xpktsizh%
          Exit If Xjr%=Xseq%
        Next Jr%
      Endif
      Exit If Rr!
    Next Wf%
    If Not Found!
      Print "Failed waiting for RR."
      @Hangup
    Endif
  Endif
  If Flush%=1
    While Xack%<>Xseq%
      For Wf%=1 To 10
        @Waitframe
        If Not Rr!
          Found!=False
          For Jr%=1 To Xwinsiz%
            Xjr%=(Xack%+Jr%) And 7
            Bput #2,Xppt%+Xjr%*Xpktsizh%,Xpktsizh%
            Exit If Xjr%=Xseq%
          Next Jr%
        Endif
        Exit If Rr!
      Next Wf%
      If Not Found!
        Print "Failed waiting for flushed RR."
        @Hangup
      Endif
    Wend
  Endif
Return
Rem ------------------------------------------------------------------
Rem CHECKSUM ROUTINE LISTING
Rem
Rem 206F0004    start: move.l 4(sp),a0    ; data packet start address.
Rem 322F0008           move.w 8(sp),d1    ; data packet length.
Rem 322F000A           move.w 10(sp),d2   ; command byte.
Rem 203C0000FFFF       move.l #$ffff,d0
Rem 4243               clr.w d3
Rem E358        ck1:   rol.w #1,d0        ; do checksum on every
Rem 2800               move.l d0,d4       ; byte in the data packet.
Rem 4285               clr.l d5
Rem 1A18               move.b (a0)+,d5
Rem D045               add.w d5,d0
Rem 3A00               move.w d0,d5
Rem B345               eor.w d1,d5
Rem D645               add.w d5,d3
Rem B084               cmp.l d4,d0
Rem 6E02               bgt.s ovck
Rem B740               eor.w d3,d0
Rem 04410001    ovck:  sub.w #1,d1
Rem 66E4               bne.s ck1
Rem 0242FFFF           and.w #$ffff,d2
Rem B142               eor.w d0,d2       ; do checksum on command byte.
Rem 303CAAAA           move.w #$aaaa,d0
Rem 9042               sub.w d2,d0       ; subtract everything from AAAA.
Rem 02800000FFFF       and.l #$ffff,d0
Rem 4E75               rts
Rem ---------------------------------------------------------------------
Rem INPUT ROUTINE LISTING
Rem
Rem 286F0004      start:  move.l 4(sp),a4     ; Buffer address.
Rem 382F0008              move.w 8(sp),d4     ; Packet size.
Rem 42A7                  clr.l -(sp)         ; Execute in superuser mode.
Rem 3F3C0020              move.w #$20,-(sp)
Rem 4E41                  trap #1
Rem 5C8F                  addq.l #6,sp
Rem 2E00                  move.l d0,d7        ; Save SUPER stack pointer.
Rem 2A39000004BA          move.l $4ba,d5      ; Get initial time.
Rem 068500000960          add.l #2400,d5      ; Twelve second timeout.
Rem 3F3C0001      next:   move.w #1,-(sp)     ; Test for character.
Rem 3F3C0001              move.w #1,-(sp)
Rem 4E4D                  trap #13
Rem 588F                  addq.l #4,sp
Rem 4A40                  tst d0
Rem 6714                  beq.s nomore        ; No character ready.
Rem 3F3C0001              move.w #1,-(sp)     ; Else, get character.
Rem 3F3C0002              move.w #2,-(sp)
Rem 4E4D                  trap #13
Rem 588F                  addq.l #4,sp
Rem 18C0                  move.b d0,(a4)+
Rem 5344                  subq.w #1,d4
Rem 670C                  beq.s out
Rem 60DC                  bra.s next
Rem 2C39000004BA  nomore: move.l $4ba,d6      ; Check timer.
Rem 9C85                  sub.l d5,d6
Rem 6DD2                  blt.s next
Rem 2F07          out:    move.l D7,-(sp)     ; Back to USER mode.
Rem 3F3C0020              move.w #$20,-(sp)
Rem 4E41                  trap #1
Rem 5C8F                  addq.l #6,sp
Rem 2004                  move.l d4,d0        ; D0=zero for success.
Rem 4E75                  rts
Rem -------------------------------------------------------------------

***********************************************************************

Rem WRITMAIL V1.0 for use with MAILTRUK  --  By John Logajan, Jan '89.
Rem                     --- PUBLIC DOMAIN ---
Rem  User configuration area.  Must be customized before using.
Rem
User$="john"                    ! your Mail name.
Fullname$="John Logajan"        ! your full name.
Machine$="logajan"              ! your machine name.
Dmain$=".mn.org"                ! your domain. (.uucp if unassigned)
Timezone$="CST"                 ! your timezone.
Gmtfact=6                       ! your timezone to GMT factor.
Mdir$="c:\mail\"                ! main mail directory.
Wecall$="bungia,ziltch"         ! list of machines you can call.
Siglines=2                      ! number of lines in signature. (Below)
Dim Sig$(Siglines)
Sig$(1)="- John Logajan @ 4248 Hamline Ave; Arden Hills, MN 55112 -"
Sig$(2)="- ...rutgers!bungia!logajan!john  or john@logajan.mn.org -"
Rem
Print "        WRITMAIL V1.0"
Gosub Help
Repeat
  Line Input "Path: ",Tpath$
  If Len(Tpath$)=0
    End
  Endif
  Path$=""
  For J=1 To Len(Tpath$)
    If Mid$(Tpath$,J,1)<>"\" Then
      Path$=Path$+Mid$(Tpath$,J,1)
    Endif
  Next J
  P=1
  K=Instr(Path$,"!")
  If K=0 Then
    Print "Path must use at least one (!) symbol."
    P=0
  Else
    Neighbor$=Left$(Path$,K-1)
    Shortpath$=Mid$(Path$,K+1)
    If Instr(Wecall$,Neighbor$)=0 Then
      Print "-";Neighbor$;"- is not in our list of sites that we can call."
      P=0
    Else
      If Len(Shortpath$)=0 Then
        Print "Cannot end path with an (!) symbol."
        P=0
      Endif
    Endif
  Endif
Until P=1
Line Input "Subject: ",Sub$
If Upper$(Sub$)="~C" Then
  End
Endif
Dim Mes$(20000)
M=0
Print
Print "Enter message, (.) alone sends message."
Print
Do
  If M<0 Then
    M=0
  Endif
  Inc M
  Line Input "",Mes$(M)
  Exit If Mes$(M)="."
  If Upper$(Mes$(M))="~C" Then
    End
  Endif
  If Upper$(Mes$(M))="~H" Then
    Dec M
    Gosub Help
  Endif
  If Upper$(Mes$(M))="~D" Then
    M=M-2
    If M<=0 Then
      M=0
      Print "No message."
    Else
      Print
      For P=1 To M
        Print Mes$(P)
      Next P
    Endif
  Endif
  If Upper$(Mes$(M))="~V" Then
    Dec M
    If M>0 Then
      Print
      For P=1 To M
        Print Mes$(P)
      Next P
    Else
      Print "No message."
    Endif
  Endif
  If Upper$(Left$(Mes$(M),3))="~R " Then
    Rdfile$=Mid$(Mes$(M),4)
    If Exist(Rdfile$) Then
      Open "I",#1,Rdfile$
      Lc=0
      While Not Eof(#1)
        Line Input #1,Mes$(M)
        Inc M
        Inc Lc
      Wend
      Close #1
      Print "File of ";Lc;" lines read into message buffer."
    Else
      Dec M
      Print "No such file!"
    Endif
  Endif
  If Upper$(Mes$(M))="~S"
    M=M-1
    For J=1 To Siglines
      M=M+1
      Mes$(M)=Sig$(J)
      Print Mes$(M)
    Next J
  Endif
Loop
If M=1 Then
  Print "No message to send -- Not sending."
  Pause 50
  End
Endif
Seq=10000+(Timer/100 And &H1FFF)
Seqf$="A"+Str$(Seq And &H1FFF Or &H1000)
Ddir$=Mdir$+Neighbor$+"\"+Seqf$+".D"
Xdir$=Mdir$+Neighbor$+"\"+Seqf$+".X"
Cdir$=Mdir$+Neighbor$+"\"+Seqf$+".C"
Open "O",#1,Ddir$
Gosub Getdate
Years=Year-1900
Print #1,"From"'Machine$;"!";User$'Dayweek$'Month$'Day'Time$'Year;Chr$(10);
Print #1,"Return-Path: <";Machine$;"!";User$;">";Chr$(10);
Print #1,"Received: by"'Machine$;Dmain$'"(MailTruk1.0)";Chr$(10);
Print #1,"        id AA";Seq;";"'Dayweek$;","'Day'Month$'Years'Time$'Timezone$;
Print #1,Chr$(10);
Print #1,"Date:"'Dayweek$;","'Day'Month$'Years'Time$'Timezone$;Chr$(10);
Print #1,"From:"'Machine$;Dmain$;"!";User$'"(";Fullname$;")";Chr$(10);
Print #1,"Message-Id: <";(((Years*100+Month)*100+Day)*100+Hgmt)*100+Minute;".";
Print #1,"AA";Seq;"@";Machine$;Dmain$;">";Chr$(10);
Print #1,"To:"'Path$;Chr$(10);
If Len(Sub$)>1 Then
  Print #1,"Subject:"'Sub$;Chr$(10);
Endif
Print #1,Chr$(10);
For P=1 To M-1
  Print #1,Mes$(P);Chr$(10);
Next P
Close #1
Open "O",#2,Xdir$
Print #2,"U"'User$'Machine$;Chr$(10);
Print #2,"F"'"D.";Neighbor$;Seqf$;Chr$(10);
Print #2,"I"'"D.";Neighbor$;Seqf$;Chr$(10);
Print #2,"C rmail"'Shortpath$;Chr$(10);
Close #2
Open "O",#3,Cdir$
Dest$="D."+Neighbor$+Seqf$
Best$="D."+Machine$+Seqf$
Xest$="X."+Machine$+Seqf$
Print #3,"S"'Dest$'Dest$'User$'"-"'Dest$'"0666"
Print #3,"S"'Best$'Xest$'User$'"-"'Best$'"0666"
Close #3
Print "Mail sent to outbound file area, awaiting UUCP."
Pause 50
End
Procedure Getdate            ! returns Month,Day,Year,Dayweek,Dayweek$,Month$
  Local K,L                  ! Hour,Minute,Second,Ampm$,Hour12,Hgmt
  Month=Val(Mid$(Date$,1,2))
  Day=Val(Mid$(Date$,4,2))
  Year=Val(Mid$(Date$,7,4))
  Hour=Val(Mid$(Time$,1,2))
  Minute=Val(Mid$(Time$,4,2))
  Second=Val(Mid$(Time$,7,2))
  If Hour>=12 Then
    Ampm$="PM"
    Hour12=Hour-12
  Else
    Ampm$="AM"
    Hour12=Hour
  Endif
  If Hour12=0 Then
    Hour12=12
  Endif
  Month$=Mid$("JanFebMarAprMayJunJulAugSepOctNovDec",Month*3-2,3)
  Hgmt=Hour+Gmtfact
  If Hgmt>=24 Then
    Hgmt=Hgmt-24
  Endif
  K=Int(0.6+1/Month)
  L=Year-K
  Dayweek=Int(13*(Month+12*K+1)/5)+Int(5*L/4)-Int(L/100)+Int(L/400)+Day-1
  Dayweek=Dayweek-(7*Int(Dayweek/7))+1
  Dayweek$=Mid$("SunMonTueWedThuFriSat",Dayweek*3-2,3)
Return
Procedure Help
  Print
  Print ". alone on line sends message."
  Print "~r filename --  reads in a file."
  Print "~d deletes previous line, and reprints message so far."
  Print "~c cancels message."
  Print "~h prints this help message."
  Print "~v reprints message so far."
  Print "~s adds predefined signature lines to message."
  Print "Paths are of the form:  neighborsite!nextsite!...!sitex!recipient"
  Print "Subject: is optional.  CR to skip it."
  Print
Return

*************************************************************************

Rem READMAIL V1.0 for use with MAILTRUK, by John Logajan, Jan '89.
Rem                       --- PUBLIC DOMAIN ---
Rem Checks mailbox and reads letters.  Saved files are always directed to the
Rem main mail directory specified below.  Please customize the next two lines.
Rem
Mdir$="c:\mail\"                 ! Main upper level mail directory.
Mysite$="logajan\"               ! Name of site mailbox directory.
Rem
Mwrk$=Mdir$+Mysite$+"WORK"
Md$=Mdir$+Mysite$+"*.*"
If Exist(Mwrk$)
  Kill Mwrk$
Endif
If Exist(Md$)
  Dir Md$ To Mwrk$
  Open "I",#3,Mwrk$
  M=0
  Bored!=False
  While Not Eof(#3)
    Line Input #3,Mfil$
    Mfix$=Mdir$+Mysite$+Mfil$
    If Exist(Mfix$)
      If Right$(Mfil$,2)=".X"
        Kill Mfix$
      Else
        If Mfil$<>"WORK"
          Inc M
          @More
          Repeat
            Cdn!=False
            Line Input "Next/Command";R$
            R$=Upper$(R$)
            If Len(R$)=0 Or Left$(R$,1)="N"
              Cdn!=True
            Endif
            If Left$(R$,1)="A" Or Left$(R$,1)="S"
              Snam$=Mid$(R$,3)
              If Len(Snam$)>0 And Len(Snam$)<13
                Open "I",#4,Mfix$
                If Left$(R$,1)="A"
                  If Exist(Mdir$+Snam$)
                    Open "A",#1,Mdir$+Snam$
                  Else
                    Print "File ";Mdir$;Snam$;" doesn't exist for appending";
                    Print " -- Creating it."
                    R$="S"
                    Open "O",#1,Mdir$+Snam$
                  Endif
                Else
                  Open "O",#1,Mdir$+Snam$
                Endif
                Lc=0
                While Not Eof(#4)
                  Inc Lc
                  Line Input #4,I$
                  Print #1,I$
                Wend
                Close #4
                Close #1
                If Left$(R$,1)="A"
                  Print "File of ";Lc;" lines appended to ";Mdir$;Snam$
                Else
                  Print "File of ";Lc;" lines saved in ";Mdir$;Snam$
                Endif
              Else
                Print "Filename - ";Snam$;" - too long."
              Endif
            Endif
            If Left$(R$,1)="D"
              Kill Mfix$
              Print "Message ";M;" deleted."
            Endif
            If Left$(R$,1)="T"
              If Exist(Mfix$)
                @More
              Else
                Print "Sorry, you have already deleted that message."
              Endif
            Endif
            If Left$(R$,1)="Q"
              Bored!=True
            Endif
            Exit If Bored!
            If Left$(R$,1)="H"
              @Hlp
            Endif
          Until Cdn!
        Endif
      Endif
    Endif
    Exit If Bored!
  Wend
  Close #3
  Kill Mwrk$
  If Not Bored!
    Print
    Print "No other mail."
  Endif
Else
  Print "No mail."
Endif
Pause 50
End
Procedure More
  Open "I",#4,Mfix$
  Fll%=Lof(#4)
  Llt%=0
  Dne!=False
  Print Chr$(27);"EMessage - ";M
  Llc%=23
  Do
    For Lc=1 To Llc%
      Line Input #4,C$
      Print C$
      Llt%=Llt%+Len(C$)
      If Eof(#4)
        Dne!=True
      Endif
      Exit If Dne!
    Next Lc
    Exit If Dne!
    Pc%=Int(Llt%/Fll%*100)
    Pmt:
    Print Chr$(27);"p--MORE--";Chr$(27)+"q(";Pc%;"%)";
    R%=Inp(2)
    Print Chr$(27);"l";
    If R%=Asc("Q") Or R%=Asc("q")
      Dne!=True
    Endif
    Exit If Dne!
    If R%=&HD
      Llc%=1
    Else
      Llc%=23
    Endif
    If R%=Asc("T") Or R%=Asc("t")
      Close #4
      Open "I",#4,Mfix$
      Fll%=Lof(#4)
      Llt%=0
      Print Chr$(27);"EMessage - ";M
      Llc%=23
    Endif
    If R%=Asc("H") Or R%=Asc("h")
      @Hlp
      Goto Pmt
    Endif
  Loop
  Close #4
Return
Procedure Hlp
  Print
  Print "During message:"
  Print "   q - skips to end."
  Print "   t - reread from the top."
  Print "   CR - read next line."
  Print "   SPACE - read next page."
  Print "   h - print this help listing."
  Print
  Print "At command prompt:"
  Print "   n or CR - read next message."
  Print "   d - delete current message."
  Print "       (Undeleted messages remain in mailbox.)"
  Print "   t - reread current message."
  Print "   s filename - save message to file."
  Print "   a filename - append message to file."
  Print "   h - print this help listing."
  Print "   q - quit back to desktop."
  Print
Return

************************************************************************

                   Packet Driver Protocol

                       G. L. Chesson
                     Bell Laboratories
                (Shortened by John Logajan)
General

                            The  technique  depends  on  the
notion of a transmission window to determine upper and lower
bounds  for  valid  sequence  numbers.   The  transmitter is
allowed to retransmit packets having sequence numbers within
the  window  until  the receiver indicates that packets have
been correctly received.  Positive acknowledgement from  the
receiver  moves  the  window; negative acknowledgement or no
acknowledgement causes retransmission.   The  receiver  must
ignore  duplicate  transmission,  detect  the various errors
that may occur, and inform the transmitter when packets  are
correctly or incorrectly received.

Packet Formats

     The protocol is defined in terms of  message  transmis-
sions  of  8-bit  bytes.   Each message includes one control
byte plus a data segment of zero or more information  bytes.
The  allowed data segment sizes range between 32 and 4096 as
determined by the formula 32(2k) where k is a 3-bit  number.
The  packet  sequence numbers are likewise constrained to 3-
bits; i.e. counting proceeds modulo-8.

     The control byte is partitioned into  three  fields  as
depicted below.

bit     7      6      5      4      3      2      1      0
        t      t      x      x      x      y      y      y

The  t  bits  indicate  a  packet  type  and  determine  the
interpretation  to be placed on the xxx and yyy fields.  The
various interpretations are as follows:

          tt      interpretation

          00      control packet
          10      data packet
          11      short data packet

A data segment accompanies all  non-control  packets.   Each
transmitter  is constrained to observe the maximum data seg-
ment size established during initial synchronization by  the
receiver  that  it  sends  to.  Type 10 packets have maximal
size data segments.  Type 11, or  short,  packets have  zero
or more data bytes but less than the maximum.  The first one
or two bytes of the data  segment  of  a  short  packet  are
count  bytes  that  indicate the difference between the max-
imum size and the number of bytes in the short segment.   If
the difference is less than 127, one count byte is used.  If
the difference exceeds 127, then the low-order seven bits of
the  difference are put in the first data byte and the high-
order bit is set as an indicator that the remaining bits  of
the difference are in the second byte.

     The sequence number of a non-control packet is given by
the  xxx  field.   Control  packets  are not sequenced.  The
newest sequence number, excluding  duplicate  transmissions,
accepted  by  a  receiver is placed in the yyy field of non-
control packets sent to the other receiver.

     There are no  data  bytes  associated  with  a  control
packet,  the  xxx field is interpreted as a control message,
and the yyy field is a value accompanying the  control  mes-
sage.   The  control messages are listed below in decreasing
priority.  That is, if several control messages  are  to  be
sent, the lower-numbered ones are sent first.

   xxx   name    yyy

    1    CLOSE   n/a
    2    RJ      last correctly received sequence number
    3    ---     ---
    4    RR      last correctly received sequence number
    5    INITC   window size
    6    INITB   data segment size
    7    INITA   window size

     The CLOSE message  indicates  that  the  communications
channel  is  to  be  shut  down.  The RJ, or reject, message
indicates that the receiver has detected an  error  and  the
sender should retransmit after using the yyy field to update
the window.                              The RR, or receiver
ready, message indicates that the receiver has  detected  no
errors;  the  yyy  field  updates  the sender's window.  The
INITA/B/C messages are used to set window and  data  segment
sizes.  Segment sizes are calculated by the formula 32(2yyy)
and window sizes may range between 1 and 7.

     Measurements of the protocol running  on  communication
links  at rates up to 9600 baud showed that a window size of
2 is optimal given a packet  size  greater  than  32  bytes.
This  means that the link bandwidth can be fully utilized by
the software.

Message Exchanges

        Initialization

     Messages are exchanged between four  cooperating  enti-
ties:  two  senders  and two receivers.  This means that the
communication channel  is  thought  of  as  two  independent
half-duplex  data paths.  For example the window and segment
sizes need not be the same in each direction.

     Initial synchronization is accomplished with two  3-way
handshakes:  two  each  of  INITA/INITB/INITC.   Each sender
transmits INITA messages repeatedly.  When an INITA  message
is received, INITB is sent in return.  When an INITB message
is received and an INITB message has  been  sent,  an  INITC
message  is  sent.   The INITA and INITB messages carry with
them the packet and window size that each receiver wants  to
use,  and  the  senders  are  supposed  to  comply.   When a
receiver has seen all three INIT messages,  the  channel  is
considered to be open.  INIT messages are ignored elsewhere.

        Data Transport

     After initial  synchronization  each  receiver  sets  a
modulo-8  incrementing  counter  R  to 0; each sender sets a
similar counter S to 1.  The value of R is always the number
of  the most recent correctly received packet.  The value of
S is always the first sequence number in the output  window.
Let  W  denote window size.  Note that the value of W may be
different for each sender.

     A sender may transmit packets with sequence numbers  in
the  range  S  to  (S+W-1) mod-8.   At any particular time a
receiver expects arriving packets to  have  numbers  in  the
range  (R+1) mod-8  to  (R+W) mod-8.  Packets must arrive in
sequence number order are are only  acknowledged  in  order.
That  is, the  next  packet a receiver will acknowledge must
have sequence number (R+1) mod-8.

     A receiver acknowledges  receipt  of  data  packets  by
arranging  for  the value of its R counter to be sent across
the channel where it will be used to update  an  S  counter.
This is done in two ways.  If data is flowing in both direc-
tions across a channel then each receiver's current R  value
is  carried in the yyy field of non-control packets.  Other-
wise  when  there  is  no  bidirectional  data  flow,   each
receiver's R value is transmitted across the link as the yyy
field of an RR control packet.

     Error handling is up to the discretion of the receiver.
It  can ignore all errors in which case transmitter timeouts
must provide for retransmission.  The receiver may also gen-
erate  RJ error control packets.  The yyy field of an incom-
ing RJ message replaces the S value of the local sender  and
constitutes  a  request  for retransmission to start at that
sequence number.

        Termination

     The CLOSE message is used to terminate  communications.
Software on either or both ends of the communication channel
may initiate termination.  In any case when one end wants to
terminate it sends CLOSE messages until one is received from
the other end or until a programmable limit on the number of
CLOSE  messages  is  reached.   Receipt  of  a CLOSE message
causes a CLOSE message to be sent.

        Framing

     The term framing is used to  denote  the  technique  by
which  the  beginning  and end of a message is detected in a
byte stream; error  control  denotes  the  method  by  which
transmission  errors  are  detected.

     A six byte framing envelope is  constructed  using  the
control  byte C of a packet and five other bytes as depicted
below.
          <DLE><k><c0><c1><C><x>
The <DLE> symbol denotes the ASCII ctrl/P character.  If the
envelope  is  to  be followed by a data segment, <k> has the
value log2(size)-4; i.e. 1 < k < 8.  If k  is  9,  then  the
envelope  represents  a  control  packet.  The <c0> and <c1>
bytes are the low-order and high-order bytes respectively of
a 16-bit checksum.        For control packets, this value is
0xAAAA minus the control byte C. 
For data packets,  the  checksum  is calculated by a program.
(John Logajan's 68000 version is below.)
The <x> byte is the exclusive-or of  <k><c0><c1><C>.   Error
control  is  accomplished  by  checking  a  received framing
envelope for compliance with the definition, and comparing a
checksum function of the data segment with <c0><c1>.

     This particular framing strategy assumes data  segments
are constant-sized: the  unused  bytes in a short packet are
actually transmitted.

------------------------------------------------------
Logajan's 68000 version of the checksum program,
as called from a GFA Basic C: call.

start: move.l 4(sp),a0      ;data packet start address
       move.w 8(sp),d1      ;data packet length
       move.w 10(sp),d2     ;command byte
       move.l #$ffff,d0
       clr.w d3
ck1:   rol.w #1,d0
       move.l d0,d4
       clr.l d5
       move.b (a0)+,d5
       add.w d5,d0
       move.w d0,d5
       eor.w d1,d5
       add.w d5,d3
       cmp.l d4,d0
       bgt.s ovck
       eor.w d3,d0
ovck:  sub.w #1,d1
       bne.s ck1
       and.w #$ffff,d2
       eor.w d0,d2
       move.w #$aaaa,d0
       sub.w d2,d0
       and.l #$ffff,d0      ;Checksum in D0.    
       rts
-----------------------------------------------------
Example session:

Note below: S = we send, R = we receive.
After the login: and password: stuff;

R Shere[=sitename]
S Soursitename
R ROK
R Pg[other protcols]
S Ug
S INITA (with our window size)
R INITA (with their window size)
S INITB (with our packet size)
R INITB (with their packet size)
S INITC (with our window size, again)
R INITC
S S workline with D.file name.   (If we have work, else H)
R RR
R SY
S RR
S data packets, short packet if need, followed by empty pkt.
R RR's
R CY
S RR
S S workline with X.file name.
R RR
R SY
S data packets
R RR's
R CY
S H    (If we are done)
R RR
R HN   (If they have work, else HY)
S RR
R S workline D.file
S RR
S SY
R RR
R data packets
S RR's
S CY
R RR
R S workline X.file
S RR
S SY
R RR
R data packets
S RR's
S CY
R RR
R H   (If they are done too.)
S RR
S HY
R RR
R HY
R RR
S CLOSE
R CLOSE
S OOOOOO
R OOOOOO (Hangup)
-----------------------------------------------------

***********************************************************************




-- 
- John M. Logajan @ Network Systems; 7600 Boone Ave; Brooklyn Park, MN 55428  -
- ...rutgers!umn-cs!ns!logajan / logajan@ns.network.com / john@logajan.mn.org -

WELTE@BUPHYC.BU.EDU (04/14/89)

Could someone send me a copy of either GFA Basic 3.0 or a GFA Run Only
program for V. 3.0?   I have 1.0 and 2.0 from the net, but they don't run
3.0. Thanks... Frank

silvert@cs.dal.ca (Bill Silvert) (04/14/89)

In article <8904131945.AA22979@bu-it.BU.EDU> WELTE@BUPHYC.BU.EDU writes:
>
>Could someone send me a copy of either GFA Basic 3.0 or a GFA Run Only
>program for V. 3.0?   I have 1.0 and 2.0 from the net, but they don't run
>3.0. Thanks... Frank

GFA Basic is a commercial product and should not be distributed (or
solicited) freely.  Version 3.0 is currently for sale at your dealer.
Version 2.0 was distributed with STart magazine several months back, so
it is very cheap, but I do not believe that it is in the public domain.

-- 
Bill Silvert, Habitat Ecology Division.
Bedford Institute of Oceanography, Dartmouth, NS, Canada B2Y 4A2
	UUCP: ...!{uunet,utai,watmath}!dalcs!biomel!bill
	CDN: biomel@cs.dal.CDN	BITNET: bs%dalcs@dalac.BITNET

apratt@atari.UUCP (Allan Pratt) (04/18/89)

In article <3234@cs.dal.ca> bill@biomel.UUCP, biomel@cs.dal.CDN writes:
> In article <8904131945.AA22979@bu-it.BU.EDU> WELTE@BUPHYC.BU.EDU writes:
> >
> >Could someone send me a copy of either GFA Basic 3.0 or a GFA Run Only
> >program for V. 3.0?   I have 1.0 and 2.0 from the net, but they don't run
> >3.0. Thanks... Frank
> 
> GFA Basic is a commercial product and should not be distributed (or
> solicited) freely.

In what I consider A Smart Move, the GFA people placed their "run-only"
interpreter in the public domain.  That way someone can buy the
whole package, write a program, and distribute the program plus
the run-only interpreter so others who don't own GFA Basic can run it.

Moreover, they actually ENCOURAGE the widest-possible distribution for
the run-only interpreter.  It's on GEnie, CI$, etc., and of course GFA
BASIC programs appear in those places, too. 

I think this was a stroke of genius on their part: it has the advantages
of distributing a crippled "demo mode" program with none of the
disadvantages (both practical and political), and it lets people write &
distribute GFA programs without narrowing THEIR potential audience to
GFA Basic owners. 

============================================
Opinions expressed above do not necessarily	-- Allan Pratt, Atari Corp.
reflect those of Atari Corp. or anyone else.	  ...ames!atari!apratt