koreth@ssyx.ucsc.edu (Steven Grimm) (03/19/89)
Submitted-by: john@logajan.mn.org (John Logajan)
Posting-number: Volume 2, Issue 28
Archive-name: mailtruk.11
The following sources (in shar format) replace and obsolete the
previous version of the programs.
Below are five files generically named MailTruk Release V1.1.
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,
in order are: MAILTRUK.DOC, MAILTRUK.LST, WRITMAIL.LST,
READMAIL.LST, and PROTOCOL.DOC. Thanks -- John Logajan.
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# mailtruk.doc
# mailtruk.lst
# writmail.lst
# readmail.lst
# protocol.doc
cat << \SHAR_EOF > mailtruk.doc
MailTruk Documentation
by
John Logajan, March 1989
4248 Hamline Ave
Arden Hills, MN 55112
john@logajan.mn.org
Note: V1.1 seems to work on 512k machines, whereas V1.0
apparently did not. Both V1.1 and V1.0 work on
1 meg machines.
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. MailTruk is the
mechanism that transports both the news and email, however this
release of MailTruk support software does not include news reading
interfaces.
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 readable listings in the public domain. Files included in the
distribution are:
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 can figure out where it is going.
Each machine, in turn, passes it along until it hopefully reaches
the 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
would 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, logon 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 in each
of the programs is correct and consistent, including the directory
names mentioned above. The variables are grouped near the
beginning of each program. You WILL have to customize these
variables for the 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 -- The MailTruk program is designed to dail out only. If
you want to re-write MailTruk to answer incoming calls -- feel
free. Just remember that everthing occurs in reverse.
Seventh -- 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. These are Internet style
paths, such as:
john@logajan.mn.org
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
Eighth -- Hopefully there is enough information in the listings
for you to set up your own site and get it operational.
Good luck.
SHAR_EOF
cat << \SHAR_EOF > mailtruk.lst
Rem MAILTRUK V1.1 -- 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, March 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,7,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
Rpktsizh%=Rpktsiz%+6
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
A$="206F0004322F0008342F000A203C0000FFFF4243E358280042851A18D0453A00B345"
A$=A$+"D645B0846E02B7400441000166E40242FFFFB142303CAAAA904202800000FFFF4E75"
Dim Chkp%(Len(A$)/4+2)
Chk%=Varptr(Chkp%(0))
For J%=0 To Len(A$)/2-1
Poke Chk%+J%,Val("&H"+Mid$(A$,J%*2+1,2))
Next J%
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
A$="286F0004382F000842A73F3C00204E415C8F2E002A39000004BA068500000960"
A$=A$+"3F3C00013F3C00014E4D588F4A4067143F3C00013F3C00024E4D588F18C05344"
A$=A$+"670C60DC2C39000004BA9C856DD22F073F3C00204E415C8F20044E75"
Dim Rcvp%(Len(A$)/4+2)
Rcv%=Varptr(Rcvp%(0))
For J%=0 To Len(A$)/2-1
Poke Rcv%+J%,Val("&H"+Mid$(A$,J%*2+1,2))
Next J%
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."
Void Xbios(15,-1,-1,-1,-1,9,-1) ! Send a break for Telebit autobaud reset.
Pause 20
Void Xbios(15,-1,-1,-1,-1,1,-1)
Pause 20
Repeat
@Ostr("ATDT"+Siteph$+"\0D") ! Dial remote site.
@Waitfor("CONNECT",60)
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
Wrklin$=String$(128," ")
Wfz%=Varptr(Wrklin$)
Wlv%=0
Repeat
@Waitdata ! Get their workline request.
Bmove Rcvbf%,Wfz%+Wlv%,Rpktsiz%
Wlv%=Wlv%+Rpktsiz%
Wllv%=Instr(Wrklin$,Chr$(0))
Until Wllv%<>0
Wrklin$=Left$(Wrklin$,Wllv%)
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%=32
@Waitframe
Endif
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 342F000A 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 -------------------------------------------------------------------
SHAR_EOF
cat << \SHAR_EOF > writmail.lst
Rem WRITMAIL V1.1 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.1"
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.1)";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, waiting for the MailTruk."
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
SHAR_EOF
cat << \SHAR_EOF > readmail.lst
Rem READMAIL V1.1 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
SHAR_EOF
cat << \SHAR_EOF > protocol.doc
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)
-----------------------------------------------------
SHAR_EOF
# End of shell archive
exit 0